元编程
元编程概念来自LISP(人工智能语言)和smalltalk。
我们写程序是直接写代码,是否能够用代码来生成未来我们需要的代码吗?这就是元编程。
例如,我们写一个类class A,能否用代码生成一个类出来?
用来生成代码的程序称为元程序metaprogram,编写这种程序就称为元编程metaprogramming。
Python语言能够通过反射实现元编程。
python中
- 所有非object类都继承自object类
- 所有类的类型包括type类都是type(由type构造)
- type类继承自object类,object类的类型也是type类
type类
type构建类
python源码
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new 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(1)
type(name,bases,dict)-> a new type
,返回一个新类型
x_class = type('newclass',(),{})
print(x_class)
print(x_class.__name__)
print(x_class.__dict__)
print(x_class.mro())
#控制台输出
#<class '__main__.newclass'>
#newclass
#{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'newclass' objects>, '__weakref__': <attribute '__weakref__' of 'newclass' objects>, '__doc__': None}
#[<class '__main__.newclass'>, <class 'object'>]
上例比较简单,我们来构建一个更复杂的类
def __init__(self,num):
print('init~~~~~~~~~')
self.num = num
def show(self):
print(self.num)
x_class = type('x',(object,),{'__init__':__init__,'show':show,'y':5})
s = x_class(100)
print(s.y)
s.show()
#控制台输出
#init~~~~~~~~~
#5
#100
可以借助type构造任何类,用代码来生成代码,这就是元编程。
构建元类
一个类可以继承自type类。注意不是继承自object类了
class Meta(type):
def __new__(cls, *args, **kwargs):#该方法是静态方法,需要一个返回值
print(cls)
print(args)
print(kwargs)
print('*' * 50)
return super().__new__(cls, *args, **kwargs)
class A(metaclass=Meta):
def __init__(self):
print('A -------- init')
class B(A):
def __init__(self):
print('B -------- init')
class C(Meta):pass #C类继承Meta元类
class D(metaclass=C):pass #D类由元类C创建
print(A.__bases__,type(A))
print(B.__bases__,type(B))
print(C.__bases__,type(C))
print(D.__bases__,type(D))
<class '__main__.Meta'>
('A', (), {'__module__': '__main__', '__qualname__': 'A', '__init__': <function A.__init__ at 0x000001D6DFEB31F8>})
{}
**************************************************
<class '__main__.Meta'>
('B', (<class '__main__.A'>,), {'__module__': '__main__', '__qualname__': 'B', '__init__': <function B.__init__ at 0x000001D6DFEB3288>})
{}
**************************************************
<class '__main__.C'>
('D', (), {'__module__': '__main__', '__qualname__': 'D'})
{}
**************************************************
(<class 'object'>,) <class '__main__.Meta'>
(<class '__main__.A'>,) <class '__main__.Meta'>
(<class '__main__.Meta'>,) <class 'type'>
(<class 'object'>,) <class '__main__.C'>
从运行结果还可以分析出_ new_ (cls, *args, **kwargs)
的参数结构
中间是一个元组('A', (), {'__module__': '__main__', '__qualname__': 'A', '__init__': <function A.__init__ at 0x000001D6DFEB31F8>})
对应(name, bases, dict)
修改代码如下
class Meta(type):
def __new__(cls,name, bases,dict)
print(cls)
print(name)
print(bases)
print(dict)
return super().__new__(cls,name, bases,dict)
从运行结果可以看出,只要元类是Meta,创建类对象时,就会调用Meta的_new_
方法
上例中,c也是元类,c–继承自–> Meta --继承自–> type。type(元类) 返回type。但是type(被metaclass修改了的元类的类)返回其元类。
元类的应用
元编程一般用于框架开发中。
开发中除非你明确的知道自己在干什么,否则不要随便使用元编程
99%的情况下用不到元类,可能有些程序员一辈子都不会使用元类
元编程总结
元类是制造类的工厂,是用来构造类的类。
构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的
type(name, bases, dict)的方式构造一个类。
元类的new方法中,可以获取元类信息、当前类、基类、类属性字典。
一辈子都不会使用元类**
元编程总结
元类是制造类的工厂,是用来构造类的类。
构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的
type(name, bases, dict)的方式构造一个类。
元类的new方法中,可以获取元类信息、当前类、基类、类属性字典。
Django、SQLAlchemy使用了 元类,让我们使用起来很方便。