前言
元编程概念来自LISP和smalltalk。
举个简单的栗子:
我们写程序是直接写代码,是否能够用代码来生成未来我们需要的代码呢?这就是元编程, ‘类’的’类’,也就是比类更高级的东西。
用来生成代码的程序成为元程序metaprogram,编写这种程序就称为元编程metaprogramming。
python通过反射来实现元编程。
python中,所有非object对象都继承自object类
所有类的类型包括type类,都是type
type类继承自object类, object类的类型也是type类
元编程
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
查看type文档很清楚的可以看到:
type(object) => the object’s type
type(name, bases, dict) => a new type 返回一个新的类型
xclass = type("a", (object,), {"a":1}) # 这里xclass只是标识符, 生成的类的真正的名字是'a'
print(xclass.__name__) #查看类的__name__
print(xclass.a) # 1 查看类属性'a'
print(xclass().a) # 1 查看实例属性'a'
print(xclass.__bases__) # object, 查看继承的类
print(xclass.mro()) # 查看mro(方法解析顺序)
print(xclass.__dict__) # 查看类的__dict__
构建元类
一个类可以继承自tyoe类, 注意不是继承自object类了。
class Meta(type):
def __new__(cls, name, bases, attrs:dict):
print(cls)
print(name)
print(bases)
print(attrs)
return super().__new__(cls, name, bases, attrs)
参数 | 含义 |
---|---|
cls | 通过元类创建的类或者继承自通过元类创建的类 |
name | 通过元类创建的类的__name__ |
bases | 通过元类创建的类所继承的类 |
attrs | 通过元类创建的类的__dict__ |
继承自type, Meta就是元类,它可以创建其他类。
分析下面通过不同方式创建类的区别:
class Metaclass(type):
def __new__(cls, name, bases, attrs:dict):
print(cls)
print(name)
print(attrs)
return super().__new__(cls, name, bases, attrs)
class A(metaclass=Metaclass): # 类型是元类,但是还是继承自Object
pass
class B(A): # 类型还是元类,但是继承自A类,A类继承自object类
pass
C = type("C", (), {}) # 这就是元类
D = Metaclass("D", (), {}) # 这就是元类
class E: # 创建的普通类
pass
class F(Metaclass): # 继承自Metaclass类
pass
print("A", type(A), A.__bases__)
print("B", type(B), B.__bases__)
print("C", type(C), C.__bases__)
print("D", type(D), D.__bases__)
print("E", type(E), E.__bases__)
print("F", type(F), F.__bases__)
-----------------------------------------------
<class '__main__.Metaclass'>
A
{'__module__': '__main__', '__qualname__': 'A'}
<class '__main__.Metaclass'>
B
{'__module__': '__main__', '__qualname__': 'B'}
<class '__main__.Metaclass'>
D
{}
A <class '__main__.Metaclass'> (<class 'object'>,)
B <class '__main__.Metaclass'> (<class '__main__.A'>,)
C <class 'type'> (<class 'object'>,)
D <class '__main__.Metaclass'> (<class 'object'>,)
E <class 'type'> (<class 'object'>,)
F <class 'type'> (<class '__main__.Metaclass'>,)
从运行结果可以看出, 只要通过一个元类创建类对象时, 就是调用元类中的__new__方法。
元类的应用
ORM编程中使用的框架sqlalchemy中就广泛使用了元编程,下面尝试使用元编程来实现sqlalchemy框架中元编程涉及到的部分功能。
class Column:
def __init__(self, filedname= None, primary_key=False, nullable=False):
self.filedname = filedname
self.primary_key = primary_key
self.nullable = nullable
class Metaclass(type): # 创建一个元类
def __new__(cls, name, bases, attrs:dict):
if "__tablename__" not in attrs:
attrs["__tablename__"] = name.lower() # 添加表名
primarykey = []
for k,v in attrs.items():
if isinstance(v, Column):
if v.filedname is None or v.filedname.strip() == "": # 如果创建的mapping类没有添加字段名,
v.filedname = k
if v.primary_key:
primarykey.append(v)
attrs["primary_key"] = primarykey
return super().__new__(cls, name, bases, attrs)
class Base(metaclass=Metaclass): # 创建一个元类,
pass
class Student(Base):
__tablename__ = "student"
id = Column(primary_key=True, nullable=False) # 使用默认filename=None构造Column类
name = Column("ben", nullable=False) #
age = Column()
# 本来构造Column实体对象的时候,参数没有填写完整,想利用元类的__new__方法,构造完整
print(Student.__dict__)
print(Student().age.filedname)
元编程总结
元类是制造类的工厂,是用来构造类的类。
构造好元类,就可以在类的定义时,使用关键字参数metaclass指定一个元类,可以使用最原始的metatype(name, bases, dict)的方式构造一个类。
元类的__new__方法中,可以获取元类信息、当前类、基类、类属性字典。
元编程一般广泛用于开发框架中。例如Django、SQLALchemy等