# 元类的深度理解
# 代码解释
class A:
    def __init__(self,name):
        self.name = name
        print('__init__方法')
    def __call__(self, *args, **kwargs):
        print('执行__call__方法')
    def __new__(cls, *args, **kwargs):
        cls.name = 'xxx'
        print('执行__new__方法')
        return object.__new__(cls)
 # 给类传递参数,会触发类的先触发__new__、在触发__init__方法
a = A('sss')
print(a.name)
print(A.name)
print('---------对象触发__call__------------')
a()
# 执行__new__方法
# __init__方法
# sss
# xxx
# ---------------------
# 执行__call__方法
print('-------------继承元类-------------------')
class MyType(type):
    def __init__(self,what,bases=None,dict=None):
        print('Mytype的__init__方法')
        super().__init__(what,bases,dict)
    def __call__(self, *args, **kwargs):  #3.触发__call__方法,在这个方法中执行自身的__init__方法
        obj = self.__new__(self,*args,**kwargs)
        print('Mytype的__call__方法')
        self.__init__(obj,*args,**kwargs)  #4.执行自身的init,进行初始化
        return obj   # 重点, 本身的self是在父类的__call__中调用了__init__函数后,赋值后,返回,不返回的话,obj返回的是None
    def __new__(cls, name, bases, attrs):
        print('MyType中的new方法')  # 最先打印
        return type.__new__(cls, name, bases, attrs)
class Foo(object,metaclass=MyType):  #1.在指定元类的第一时间,回去执行Mytype中执行 它的__new__方法,再执行它的__init__方法
    # __metaclass__ = MyType  #py3中不能使用这种方法指定元类
    def __init__(self,name):
        print('Foo类中的__init__方法')
        self.name = name
    def __new__(cls, *args, **kwargs):
        print('Foo中的__new__方法')
        return object.__new__(cls)
    def __call__(self):
        print('Foo中的call方法')
obj = Foo('xx')  #2.实例化Foo类,最先执行类得__new__方法,返回一个空间空间
print(obj.name)
obj()
# MyType中的new方法
# Mytype的__init__方法
# Foo中的__new__方法
# Mytype的__call__方法
# Foo类中的__init__方法
# xx
# Foo中的call方法
print('--------------一般继承----------------------')
class A:
    def __call__(self, *args, **kwargs):
        print('A的__call__方法')
class B(A):
    def __init__(self,name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        print('B的__new__方法')
        return object.__new__(cls)
b = B('xxx')
b()
# B() # 报错,只能实例化
a = A()
a()   # 对应才能触发__call__方法,B()不能, A()也不能
# B的__new__方法
# A的__call__方法
# A的__call__方法
# Metaclass的使用
实例一:
class MyType(type): def __init__(self, *args, **kwargs): print('MyType创建类',self) super(MyType, self).__init__(*args, **kwargs) def __call__(self, *args, **kwargs): obj = super(MyType, self).__call__(*args, **kwargs) print('类创建对象', self, obj) return obj class Foo(object,metaclass=MyType): user = 'wupeiqi' age = 18 obj = Foo()实例二
class MyType(type): def __init__(self, *args, **kwargs): super(MyType, self).__init__(*args, **kwargs) def __call__(cls, *args, **kwargs): v = dir(cls) obj = super(MyType, cls).__call__(*args, **kwargs) return obj class Foo(MyType('MyType', (object,), {})): user = 'wupeiqi' age = 18 obj = Foo()实例三
class MyType(type): def __init__(self, *args, **kwargs): super(MyType, self).__init__(*args, **kwargs) def __call__(cls, *args, **kwargs): v = dir(cls) obj = super(MyType, cls).__call__(*args, **kwargs) return obj def with_metaclass(arg,base): return MyType('MyType', (base,), {}) class Foo(with_metaclass(MyType,object)): user = 'wupeiqi' age = 18 obj = Foo()# 总结
1、执行顺序? 在实例化一个继承元类的类时,先在加载时就会触发继承的元类的__new__方法、__init__方法,在实例时,先触发类的__new__方法、在触发元类的__call__方法,在__call__方法中触发self.__init__方法,最后返回call中创建的对象 2、那么__new__在整个过程中扮演什么角色? __new__方法主要用来创建类空间以及类 3、在object的部分代码,使用c写的(CPython),也就是说源码不可见
# 元类剖析
在大多数语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这一点仍然成
立:
>>> class ObjectCreator(object):
... pass
... 
>>> my_object = ObjectCreator() 
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
但是在Python中类也是对象. 是的,对象. 每当你用到关键字 class , Python就会执行它并且建立一个对象.例如:
>>> class ObjectCreator(object): 
... pass 
...
上面代码在内存里创建了名叫"ObjectCreator"的对象. 这个对象(类)有生成对象(实例)的能力,这就是为什么叫做类. 它是个对象,所以:
1、你可以把它赋值给一个变量 
2、你可以赋值它 
3、你可以给它添加属性
4、你个以作为函数参数来传递它
>>> print(ObjectCreator) # 你可以打印一个类,因为它是一个对象 
<class '__main__.ObjectCreator'> 
>>> def echo(o): 
... print(o) 
... 
>>> echo(ObjectCreator) # 你可以把类作为参数传递 
<class '__main__.ObjectCreator'> 
>>> print(hasattr(ObjectCreator, 'new_attribute')) 
False 
>>> ObjectCreator.new_attribute = 'foo' # 可以给一个类添加属性 
>>> print(hasattr(ObjectCreator, 'new_attribute')) 
True 
>>> print(ObjectCreator.new_attribute) 
foo 
>>> ObjectCreatorMirror = ObjectCreator # 可以把类赋值给一个变量 
>>> print(ObjectCreatorMirror.new_attribute) 
foo 
>>> print(ObjectCreatorMirror()) 
<__main__.ObjectCreator object at 0x8997b4c>
# 动态创建类
因为类也是对象,你可以在运行时动态的创建它们,就像其他任何对象一样。 首先,你可以在函数中创建类,使用class关键字即可:
>>> def choose_class(name): 
...   if name == 'foo': 
...      class Foo(object): 
... 				pass 
... 		 return Foo # 返回一个类不是一个实例 
...   else: 
... 		 class Bar(object): 
... 				pass 
... 	   return Bar 
... 
>>> MyClass = choose_class('foo') 
>>> print(MyClass) # 返回一个类不是一个实例 
<class '__main__.Foo'> 
>>> print(MyClass()) # 你可以在类里创建一个对象 
<__main__.Foo object at 0x89c6d4c>
但这还不够动态,因为你仍然需要自己编写整个类的代码. 既然类是对象,那么肯定有什么东西来生成它. 当你使用关键字 objects ,Python自动的创建对象.像Python中大多数的东西一样,他也给你自 己动手的机会. 记得函数 type 吗?这个古老好用的函数能让你知道对象的类型是什么:
>>> print(type(1)) 
<type 'int'> 
>>> print(type("1")) 
<type 'str'> 
>>> print(type(ObjectCreator)) 
<type 'type'> 
>>> print(type(ObjectCreator())) 
<class '__main__.ObjectCreator'>
这里, type 有一种完全不同的能力,它也能动态的创建类. type 可以接受一个类的描述作为参数,然后返回一个类. (我知道,根据传入参数的不同,同一个函数拥有两种完全不同的用法是一件很傻的事情,但这在Python中是为了保持向后兼容性)
# type(类名, 父类名的元组 (针对继承情况,可以为空), 包含属性的字典(名称和值))
>>> class MyShinyClass(object): 
  ... pass
>>> MyShinyClass = type('MyShinyClass', (), {}) # 返回类对象 
>>> print(MyShinyClass) 
<class '__main__.MyShinyClass'> 
>>> print(MyShinyClass()) # 创建一个类的实例 
<__main__.MyShinyClass object at 0x8997cec>
type 可以接受一个字典来定义类的属性:
# 最终效果
>>> class Foo(object): 
... bar = True
# type实现
>>> Foo = type('Foo', (), {'bar':True})
>>> print(Foo) 
<class '__main__.Foo'> 
>>> print(Foo.bar) 
True 
>>> f = Foo() 
>>> print(f) 
<__main__.Foo object at 0x8a9b84c> 
>>> print(f.bar) 
True
# 继承最终效果
>>> class FooChild(Foo): 
  ... pass
>>> FooChild = type('FooChild', (Foo,), {}) 
>>> print(FooChild) 
<class '__main__.FooChild'> 
>>> print(FooChild.bar) # bar从Foo继承 
True
要是在类中添加方法,你要做的就是把函数名写入字典就可以了,不懂可以看下面:
>>> def echo_bar(self): 
... 	print(self.bar) 
... 
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar}) 
>>> hasattr(Foo, 'echo_bar') 
False 
>>> hasattr(FooChild, 'echo_bar') 
True 
>>> my_foo = FooChild() 
>>> my_foo.echo_bar()
True
你可以看到,在Python中,类也是对象,你可以动态的创建类。这就是当你使用关键字class 时Python在幕后做的事情,而这就是通过元类来实现的。
# 什么是元类**(终于到正题了)**
元类就是创建类的东西. 你是为了创建对象才定义类的,对吧? 但是我们已经知道了Python的类是对象. 这里,元类创建类.它们是类的类,你可以把它们想象成这样:
MyClass = MetaClass() 
MyObject = MyClass()
你已经看到了 type 可以让你像这样做:
MyClass = type('MyClass', (), {})
这是因为 type 就是一个元类. type 是Python中创建所有类的元类. 现在你可能纳闷为啥子 type 用小写而不写成 Type ? Python中所有的东西都是对象.包括整数,字符串,函数还有类.所有这些都是对象.所有这些也都 是从类中创建的:
>>> age = 35 
>>> age.__class__ 
<type 'int'> 
>>> name = 'bob' 
>>> name.__class__ 
<type 'str'> 
>>> def foo(): 
			pass 
>>> foo.__class__ 
<type 'function'> 
>>> class Bar(object): 
			pass 
>>> b = Bar() 
>>> b.__class__ 
<class '__main__.Bar'>
那么, __class__ 的 __class__ 属性是什么?
>>> age.__class__.__class__ 
<type 'type'> 
>>> name.__class__.__class__ 
<type 'type'> 
>>> foo.__class__.__class__ 
<type 'type'> 
>>> b.__class__.__class__ 
<type 'type'>
所以,元类就是创建类对象的东西. 如果你愿意你也可以把它叫做'类工厂'. type 是Python的内建元类,当然,你也可以创建你自己 的元类
# **__metaclass__**属性
当你创建一个函数的时候,你可以添加__metaclass__属性:
class Foo(object):
	__metaclass__ = something
	... [...]
如果你这么做了,Python就会用元类来创建类Foo. 小心点,这里面有些技巧. 你首先写下 class Foo(object ,但是类对象 Foo 还没有在内存中创建. Python将会在类定义中寻找 __metaclass__ .如果找打了就用它来创建类对象 Foo .如果没找到, 就会默认用 type 创建类. 把下面这段话反复读几次。
当你写如下代码时 :
class Foo(Bar): pass
Python将会这样运行:
在 Foo 中有没有 __metaclass__ 属性?
如果有,Python会在内存中通过 __metaclass__ 创建一个名字为 Foo 的类对象(我说的是类对
象,跟紧我的思路).
如果Python没有找到 __metaclass__ ,它会继续在Bar(父类)中寻找 __metaclass__ 属性 ,并
尝试做和前面同样的操作.
如果Python在任何父类中都找不到 __metaclass__ ,它就会在模块层次中去寻
找 __metaclass__ ,并尝试做同样的操作。
如果还是找不到 __metaclass__ ,Python就会用内置的 type 来创建这个类对象。
现在的问题就是,你可以在 __metaclass__ 中放置些什么代码呢?
答案就是:可以创建一个类的东西。
# 自定义元类
元类的主要目的就是为了当创建类时能够自动地改变类.
通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类.
假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方
法可以办到,但其中一种就是通过在模块级别设定 __metaclass__ .
采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有
的属性都改成大写形式就万事大吉了。
幸运的是,__metaclass__ 实际上可以被任意调用,它并不需要是一个正式的类(我知道,某
些名字里带有'class'的东西并不需要是一个class,画画图理解下,这很有帮助)。
所以,我们这里就先以一个简单的函数作为例子开始。
# 元类会自动将你通常传给'type'的参数作为自己的参数传入 
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    """返回一个将属性列表变为大写字母的类对象 """
    # 选取所有不以'__'开头的属性,并把它们编程大写
    uppercase_attr = {}
    print('xx')
    for name, val in future_class_attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[
                name] = val  # 用'type'创建类
    return type(future_class_name, future_class_parents, uppercase_attr)
class Foo(object, metaclass=upper_attr):  # global __metaclass__ won't work with "object" though
    # 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中
    bar = 'bip'
print(hasattr(Foo, 'bar'))  # 输出: False
print(hasattr(Foo, 'BAR'))  # 输出: True
f = Foo()
print(f.BAR)  # 输出: 'bip'
← Python内置方法 函数 →