Python 元类
Python 元类(metaclass)
对象
Python 中一切皆对象,连类也不例外。
对象中包含三个关键性属性:
- 标识 使用
id()
方法查看 - 对象值
- 类型 使用
type()
方法查看
类与对象
Python 中使用 class 关键字定义类,通过定义的类生成类实例。实例称之为实例对象。Python 中类是一个对象,所有内建类型的类型都是 type,这个 type 就是元类,元类就是 Python 中的造物主。
道生一,一生二,二生三,三生万物。
道 即是 type
一 即是 metaclass(元类,或者叫类生成器)
二 即是 class(类,或者叫实例生成器)
三 即是 instance(实例)
万物 即是 实例的各种属性与方法,我们平常使用python时,调用的就是它们。
type>>>metaclass>>>class>>>instance
^ |
|<<|
# class 关键词创建
class Base:
counter = 10
class Derived(Base):
def get_counter(self):
return self.counter
x = Derived()
x.get_counter()
# 动态创建
Base = type('Base', (), {'counter': 10})
Derived = type('Derived', (Base,), dict(get_counter=lambda self: self.counter))
x = Derived()
x.get_counter()
# type 函数
type(name, bases, dict):
name: 字符串类型,存放新类的名字
bases: 元组(tuple)类型,指定类的基类/父类
dict: 字典类型,存放该类的所有属性(attributes)和方法(method)
现在我们都知道类(对象)可以使用 class 关键字创建,我们还知道类(对象)的类型是 type,既然知道了它的类型是 type,那么肯定可以通过 type(元类)来创建。
类的创建过程
- 确定类的父类是否包含 metaclass 参数,没有就执行下一步
- 确定类的父类的父类是否包含 metaclass 参数,没有就执行下一步
- 使用默认元类 type
定义元类
函数方式
def upper_attr(cls, base, attr):
attrs = ((name, value) for name, value in attr.items() if not namw.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return type(cls, base, attr)
def Foo(object):
__metaclass__ = upper_attr
bar = 'bar'
print hasattr(Foo, 'bar')
# 输出: False
print hasattr(Foo, 'BAR')
# 输出:True
f = Foo()
print f.BAR
# 输出:'bar'
类方式
# 请记住,'type'实际上是一个类,就像'str'和'int'一样。所以,你可以从type继承
# __new__ 是在__init__之前被调用的特殊方法,__new__是用来创建对象并返回之的方法,__new_()是一个类方法
# 而__init__只是用来将传入的参数初始化给对象,它是在对象创建之后执行的方法。
# 你很少用到__new__,除非你希望能够控制对象的创建。这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情。还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用,下面我们可以单独的讨论这个使用
class UpperAttrMetaclass(type):
def __new__(cls, name, bases, dct):
attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
元类的应用
- ORM
- 限定子类行为
- 注册所有子类
实例化过程
实例:__call__
»> __new__
»> __init__
»> instance
类实例:__prepare__
»> __call__
»> __new__
»> __init__
»> class instance
特殊函数签名
>>> class Meta(type):
... @classmethod
... def __prepare__(mcs, name, bases, **kwargs):
... print(' Meta.__prepare__(mcs=%s, name=%r, bases=%s, **%s)' % (
... mcs, name, bases, kwargs
... ))
... return {}
... def __new__(mcs, name, bases, attrs, **kwargs):
... print(' Meta.__new__(mcs=%s, name=%r, bases=%s, attrs=[%s], **%s)' % (
... mcs, name, bases, ', '.join(attrs), kwargs
... ))
... return super().__new__(mcs, name, bases, attrs)
... def __init__(cls, name, bases, attrs, **kwargs):
... print(' Meta.__init__(cls=%s, name=%r, bases=%s, attrs=[%s], **%s)' % (
... cls, name, bases, ', '.join(attrs), kwargs
... ))
... return super().__init__(name, bases, attrs)
... def __call__(cls, *args, **kwargs):
... print(' Meta.__call__(cls=%s, args=%s, kwargs=%s)' % (
... cls, args, kwargs
... ))
... return super().__call__(*args, **kwargs)
...
元类 super 方法
import random
class Meta(type):
# 类变量
_instance = None
def __call__(cls, *args, **kwargs):
print('meta: call: %s' % cls)
if cls._instance is None:
cls._instance = super(Meta, cls).__call__(*args, **kwargs)
print("meta: call: returning %s@%s" % (cls._instance.__class__, id(cls._instance)))
return cls._instance
class ClassA(object):
__metaclass__ = Meta
def __new__(cls, *args, **kwargs):
print('classA: new')
return super(ClassA, cls).__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
self.val = random.randint(1, 1000)
print('classA: init')
class ClassB(object):
__metaclass__ = Meta
def __new__(cls, *args, **kwargs):
print('classB: new')
return super(ClassB, cls).__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
print('classB: init')
self.val = random.randint(1, 1000)
class ClassC(ClassB):
def __new__(cls, *args, **kwargs):
print('classC: new')
return super(ClassC, cls).__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
print('classC: init')
super(ClassC, self).__init__(self, *args, **kwargs)
self.test = 3
def main():
a1 = ClassA()
b1 = ClassB()
a2 = ClassA()
b2 = ClassB()
c1 = ClassC()
print(a1.val)
print(b1.val)
print(a2.val)
print(b2.val)
if __name__ == '__main__':
main()
x = Foo() == type(Foo).__call__(Foo)
元类中的 super() == super(Singleton, cls)
方法调用了待实例化的类 __new__ and __init__
super(cls, instance)
(isinstance(instance, cls) must be True), the method is selected from the next class ininstance.__class__.__mro__
starting frominstance.__class__
.super(cls0, cls1)
(issubclass(cls1, cls0) must be True), the method is selected from next class incls1.__mro__
starting from cls0