元编程的概念来自LISP和smalltalk。
用来生成代码的程序称为元程序metaprogram,编写这种程序就称为元编程metaprogramming。
python主要通过反射来实现元编程。
Python中
所有非object类都继承自Object类
所有类的类型包括type类都是type
type类继承自object类,object类的类型也是type类
class type(object):
def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
构建
def __init__(self):
self.x = 1000
def show(self):
return self.__dict__
XClass = type('myclass', (object,), {'a':100, 'b': 'string', 'show':show, '__init__':__init__}) # 字典是类属性 print(XClass)
print(XClass)
print(XClass.__name__)
print(XClass.__dict__)
print(XClass.mro())
XClass().show()
可以借助type构造任何类,用代码生成代码,这就是元编程。
一个类可以继承自type类
class ModelMeta(type):
def __new__(cls, *args):
print(cls)
print(*args)
return super().__new__(cls, *args)
继承自type,ModelMeta就是元类,它可以创建出其他类。
class ModelMeta(type): # 继承自type
def __new__(cls, name, bases, attrs: dict):
print(cls)
print(name)
print(bases)
print(attrs)
print("--------")
return super().__new__(cls, name, bases, attrs)
# 第一种 使用metaclass关键字参数指定元类
class A(metaclass=ModelMeta):
id = 100
def __init__(self):
self.x = 2000
# 第二种 B继承自A后,依然是从ModelMeta的类型
class B(A): # 继承
pass
# 第三种 元类就可以使用下面的方式创建新的类
C = ModelMeta('Class', (), {'y': 200})
print(type(A))
print(type(B))
print(type(C))
从运行结果还可以分析出__new__(cls, *args)
的参数结构
中间是一个元组 ('A', (), {'__init__':
对应 (name, bases, dict)
从运行结果可以看出,只要元类是ModelMeta,创建类对象时,就会调用ModelMeta的__new__
方法
class Field:
def __init__(self, fieldname=None, pk=False, nullable=False):
self.fieldname = fieldname
self.pk = pk
self.nullable = nullable
def __repr__(self):
return "" .format(self.fieldname)
class ModelMeta(type): # 继承自type
def __new__(cls, name, bases, attrs: dict):
print(cls)
print(name)
print(bases)
print(attrs, '-------------')
# 使用元类动态注入表名
tblname = '__tablename__'
if tblname not in attrs.keys():
attrs[tblname] = name
primarykeys = []
for k, v in attrs.items():
if isinstance(v, Field):
print(k)
print(v)
print(v.fieldname)
if v.fieldname is None:
v.fieldname = k # 没有名字则使用属性名
if v.pk:
primarykeys.append(v)
attrs['__primarykeys__'] = primarykeys
return super().__new__(cls, name, bases, attrs)
class ModelBase(metaclass=ModelMeta):
pass
class Student(ModelBase):
id = Field(pk=True, nullable=False)
name = Field('username', nullable=False)
age = Field()
print('----------------')
print(Student.__dict__)
元类是制造类的工厂,是生成类的类。
构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的metatype(name,
bases, dict)的方式构造一个类。
元类的 __new__()
方法中,可以获取元类信息、当前类、基类、类属性字典。
元编程一般用于框架开发中。