1、元编程:
元编程 概念来自 LISP 和 smalltalk
我们写程序 是直接写代码,是否能够用代码来生成未来我们需要的代码,这就是元编程。
用阿里生成代码的程序称为元程序,metaprogram,编写这种程序就称为元编程。
Python 语言能够通过反射实现 元编程
python 中;
所有非object 类都继承自object 类
所有类的类型包括 type类 都是type
type类 继承自object 类,object类的类型也是type类
2、type类
type构建类:
1 class type(object): 2 """ 3 type(object_or_name, bases, dict) 4 type(object) -> the object's type ----> 返回对象的类型,例如 type(10) 5 type(name, bases, dict) -> a new type ----> 返回一个新的类型 6 """
测试:
1 XClass = type('mycalss', (object,), {'a':100, 'b':'string'}) 2 3 print(XClass) 4 print(XClass.__dict__) 5 print(XClass.__name__) 6 print(XClass.__bases__) 7 print(XClass.mro())
结果:
<class '__main__.mycalss'> {'a': 100, 'b': 'string', '__module__': '__main__', '__dict__': <attribute '__dict__' of 'mycalss' objects>, '__weakref__': <attribute '__weakref__' of 'mycalss' objects>, '__doc__': None} mycalss (<class 'object'>,) [<class '__main__.mycalss'>, <class 'object'>]
mycalss 是创建类的 标识符
(objects,): 基类
类似命名元组
测试:
1 def __init__(self): 2 self.x = 100 3 4 def show(self): 5 print(self.__dict__) 6 print(self.x) 7 8 XClass = type('myclass', (object,), {'a':100,'b':111, 'show':show, '__init__':__init__}) 9 10 print(XClass) 11 print(XClass.__name__) 12 print(XClass.__dict__) 13 print(XClass.mro()) 14 15 print('-' * 40) 16 XClass().show()
结果:
1 <class '__main__.myclass'> 2 myclass 3 {'a': 100, 'b': 111, 'show': <function show at 0x00000000023322F0>, '__init__': <function __init__ at 0x00000000004BC1E0>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'myclass' objects>, '__weakref__': <attribute '__weakref__' of 'myclass' objects>, '__doc__': None} 4 [<class '__main__.myclass'>, <class 'object'>] 5 ---------------------------------------- 6 {'x': 100} 7 100
可以借助type 构造 任何类,用代码来生成代码,这就是元 编程
3、构造元类:
一个类可以继承自type 类,注意不是继承自 object 类了。
1 class ModelMeta(type): 2 def __new__(cls, *args, **kwargs): 3 print(cls) 4 print(args) # 就是 type(name,bases, dict)的参数 5 print(kwargs) 6 print('------------------------------') 7 return super().__new__(cls, *args, **kwargs) 8 # 此处的 ModelMeta 就是元类,继承自type,它可以创建出其他类 9 10 # 第一种 使用metaclass 关键字 参数指定元类 11 class A(metaclass=ModelMeta): 12 id = 100 13 14 def __init__(self): 15 print(' ==== A ====') 16 print(A.__class__) 17 print(A.mro()) 18 print('~~~~~~~~~~~~~~====~~~~~~~~~~') 19 # 第二种 B继承自 A 后,依然是从ModelMeata的类型 20 class B(A): 21 def __init__(self): 22 print('==== B ====') 23 24 print(B.__class__) 25 print(B.mro()) 26 print('~~~~~~~~~~~~====~~~~~~~~~~~~') 27 # 第三种 元类就可以使用下面的方式创建新的类 28 C = ModelMeta('C', (), {}) 29 print(C.__class__) 30 print(C.mro()) 31 print('~~~~~~~~~~~~====~~~~~~~~~~~~') 32 33 # D,E 是type的 实例, 没有使用自定义的元类,所以默认使用type 34 class D:pass 35 E = type('E', (), {}) 36 37 class F(ModelMeta):pass # 和A 不一样,没有使用关键字 metaclass 38 39 print('=============================') 40 print(type(A), A.__bases__) 41 print(type(B), B.__bases__) 42 print(type(C)) 43 print(type(D)) 44 print(type(E)) 45 print(type(F), F.__bases__)
结果:
1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt14.py 2 <class '__main__.ModelMeta'> 3 ('A', (), {'__module__': '__main__', '__qualname__': 'A', 'id': 100, '__init__': <function A.__init__ at 0x00000000029422F0>}) 4 {} 5 ------------------------------ 6 <class '__main__.ModelMeta'> 7 [<class '__main__.A'>, <class 'object'>] 8 ~~~~~~~~~~~~~~====~~~~~~~~~~ 9 <class '__main__.ModelMeta'> 10 ('B', (<class '__main__.A'>,), {'__module__': '__main__', '__qualname__': 'B', '__init__': <function B.__init__ at 0x0000000002942378>}) 11 {} 12 ------------------------------ 13 <class '__main__.ModelMeta'> 14 [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>] 15 ~~~~~~~~~~~~====~~~~~~~~~~~~ 16 <class '__main__.ModelMeta'> 17 ('C', (), {}) 18 {} 19 ------------------------------ 20 <class '__main__.ModelMeta'> 21 [<class '__main__.C'>, <class 'object'>] 22 ~~~~~~~~~~~~====~~~~~~~~~~~~ 23 ============================= 24 <class '__main__.ModelMeta'> (<class 'object'>,) 25 <class '__main__.ModelMeta'> (<class '__main__.A'>,) 26 <class '__main__.ModelMeta'> 27 <class 'type'> 28 <class 'type'> 29 <class 'type'> (<class '__main__.ModelMeta'>,) 30 31 Process finished with exit code 0
修改代码如下:
1 class ModelMeta(type): 2 def __new__(cls, name, bases, dict): 3 print(cls) 4 print(name) 5 print(dict) 6 print('------------------------------') 7 return super().__new__(cls, name, bases, dict) 8 # 此处的 ModelMeta 就是元类,继承自type,它可以创建出其他类 9 10 # 第一种 使用metaclass 关键字 参数指定元类 11 class A(metaclass=ModelMeta): 12 id = 100 13 14 def __init__(self): 15 print(' ==== A ====')
从结果看出,只要元类是ModelMeta,创建类对象时,就会调用MoelMeta的 __new__方法
元类的应用:
模拟创建表格式
1 class Field:# 定义字段的属性类 2 def __init__(self, fieldname=None,pk=False, nullable=True): 3 self.fieldname= fieldname 4 self.pk = pk 5 self.nullable = nullable 6 7 def __repr__(self): 8 return '<Field {}'.format(self.fieldname) 9 10 class ModelMeta(type): 11 def __new__(cls, name, bases, attrs:dict): 12 print(cls) 13 print(name) 14 print(bases) 15 print('=====', attrs,'=====') 16 17 if '__tablename__' not in attrs.keys(): 18 attrs['__tablename__'] = name 19 20 primarykey = [] 21 for k, v in attrs.items(): 22 if isinstance(v, Field): 23 if v.fieldname is None: 24 v.fieldname = k 25 if v.pk: 26 primarykey.append(v) 27 attrs['__primarykey__'] = primarykey 28 29 return super().__new__(cls, name, bases, attrs) 30 31 class ModelBase(metaclass=ModelMeta): 32 ''' 从 ModelBases 继承的类的类型都是ModelMeta ''' 33 pass 34 35 class Students(ModelBase): 36 id = Field(pk=True, nullable = False) 37 name = Field('username', nullable=False) 38 age = Field() 39 40 print('====================================') 41 print(Students.__dict__)
结果:
1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt14.py 2 <class '__main__.ModelMeta'> 3 ModelBase 4 () 5 ===== {'__module__': '__main__', '__qualname__': 'ModelBase', '__doc__': ' 从 ModelBases 继承的类的类型都是ModelMeta '} ===== 6 <class '__main__.ModelMeta'> 7 Students 8 (<class '__main__.ModelBase'>,) 9 ===== {'__module__': '__main__', '__qualname__': 'Students', 'id': <Field None, 'name': <Field username, 'age': <Field None} ===== 10 ==================================== 11 {'__module__': '__main__', 'id': <Field id, 'name': <Field username, 'age': <Field age, '__tablename__': 'Students', '__primarykey__': [<Field id], '__doc__': None} 12 13 Process finished with exit code 0
元编程总结:
元类是制造类的工厂,是生成类的类
构造好元类,就可以在类定义的时候,使用关键字参数 metaclass 指定元类,可以使用最原始的metatype(name,base,dict)的方式 构造一个类
元类的__new__()方法中,可以获取元类的信息,当前类,基类,类属性字典
元编程一般用于框架开发中,Django SQLAlchemy 都使用了 元类。