Python中的元编程
文章目录
- Python中的元编程
- type类
- 构建元类
- 元类的应用
- 元编程总结
- 元编程概念来自LISP和smalltalk。
- 如果自己写的代码,能生成我们需要的代码。这就是元编程。即用代码生成代码。或者说用代码生成特定的类。例如:常用的class类,是否能够用代码直接生成class类,而不是用关键字class来定义。
- 用来生成代码的程序称为元编程metaprogram,编写这种程序就称为元编程metaprogramming
- Python语言能够通过反射实现元编程。
- Python中
- 所有非object类都继承自object类
- 所有类的类型包括type类都是type
- type类继承自object类,object类的类型也是type类
type类
- type构建类
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(object) -> the object's type
,返回对象的类型,例如type(10) -
type(name,bases,dict) -> a new type
返回一个新的类型
- name 新类的类名
- bases 新类的继承关系,一个元组,默认继承object
- dict 新类的字典,可以为新类添加类属性
- 简单示例:
XClass = type("myclass",(object,),{"a":100,"b":"string"}) # 字典是类属性
print(XClass)
print(XClass.__dict__)
print(XClass.__name__)
print(XClass.__bases__)
print(XClass.mro())
- 使用type构建复查的类
def init(self):
self.x = 1000
def show(self):
print("我是实例方法",self.__dict__)
@classmethod
def show1(cls):
print("类方法",cls)
XClass = type("myclass",(object,),{"a":100,"b":"string",
"show1":show1,"show":show,"__init__":init})
print(XClass)
print(XClass.__name__)
print(XClass.__dict__)
print(XClass.mro())
print("- "*30)
# 使用类方法
XClass.show1()
# 使用实例方法
xclass = XClass()
xclass.show()
print(xclass.x)
- 可以借助type构造任何类,用代码来生成代码,这就是元编程。
构建元类
- 如果一个类继承了type类,那么这个类就是个元类。元类可以直接用来使用,元类可以用来创造类。
- 在定义一个类的时候,会使用该类所指定的元类中的
__new__
方法类创建该类。 - 默认类的元类是
metaclass = type
可以在类的继承体系括号中添加该参数为类指定该元类 - 如果一个类的元类会从父类中继承下来。
class Mode(type):
def __new__(cls,*args,**kwargs):
print(cls)
print(args)
print(kwargs)
print()
return super().__new__(cls,*args,**kwargs) #调用父类方法构建实例
class A(metaclass=Mode): #改变A类的元类,默认元类是type
id = 1000
def __init__(self):
print("A.init--------------")
# 第二种 B继承A后,元类依然是A中所指定的元类
class B(A):
def __init__(self):
print("B.init~~~~~~~~~~~")
# 第三种,元类可以使用下面的方式创建新的类
C = Mode("C",(),{})
# D、E是type的实例
class D:pass #等价于 D = type("D",(),{})
E = type("E",(),{})
class F(Mode):pass
print("= "*40)
print(type(A),A.__bases__)
print(type(B),B.__bases__)
print(type(C),C.__bases__)
print()
print(type(D),D.__bases__)
print(type(E),E.__bases__)
print()
print(type(F),F.__bases__)
- 从运行结果还可以分析出
__new__(cls,*args,**kwargs)
的参数解构。中间是一个元组('A', (), {'__module__': '__main__', '__qualname__': 'A', 'id': 1000, '__init__': <function A.__init__ at 0x0000023A6FCCF620>})
对应(name,bases,dict)
- 由此可以修改自定义元类代码为:
class Mode(type):
def __new__(cls,name,bases,dt:dict):
print(cls)
print(name)
print(bases)
print(dt,"--------")
return super().__new__(cls,name,bases,dt) #调用父类方法构建实例
- 从运行结果可以看出,只要元类是Mode,创建类对象时,就会调用Mode的
__new__
方法。 - 上例中,F也是元类,F–继承自–》Mode–继承自–》type。type(元类)返回type。但是type(被metaclass修改了的元类的类返回其元类。)
元类的应用
- 本示例模拟sqlAlchemy中标定义时继承的Base,和字段类型Column的原理。(这里不做描述器的演示)
class Column:
def __init__(self,fieldname=None,pk=False,nullable=False):
self.fieldname = fieldname
self.pk = pk
self.nullable = nullable
def __repr__(self):
return "<{} {}>".format(__class__.__name__,self.fieldname)
class ModelMeta(type):
def __new__(cls,name,bases,attrs:dict):
print(name,bases,attrs)
if "__tablename__" not in attrs:
attrs["__tablename__"] = str.lower(name)
primarykeys = []
# 为类动态绑定属性
for k,v in attrs.items():
if isinstance(v,Column):
if v.fieldname is None or v.fieldname.strip() == "":
v.fieldname = k #指段没有名字使用属性名
if v.pk:
primarykeys.append(v)
attrs["__primarykeys__"] = primarykeys
return super().__new__(cls,name,bases,attrs)
class Base(metaclass=ModelMeta):
"""继承Base的类的元类都是ModelMety"""
pass
class Student(Base):
id = Column(pk=True,nullable=False)
name = Column("username",nullable=False)
ags = Column()
print("- "*30)
print(Student.__dict__)
元编程总结
- 元类是制造类的工厂,是用来构造类的类。
- 构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的metatype(name,bases,dict)的方式构造一类。
- 元类的
__new__()
方法中,可以获取元类信息、当前类、基类、类属性字典。 - 元编程一般用于框架开发中。
- 开发中除非你明确的知道自己在干什么,否则不要随便使用元编程
- Django、SQLAlchemy使用了元类,让我们使用起来很方便。