python 3 黑色魔法元类初探

最近读django源码,发现必须了解元类才能理解一些很神奇的行为.

发现元类实际上是控制class的创建过程.比如类B继承某个看似平淡无奇的类A之后,你在类B中定义的属性或方法可能会遭到彻底改变.

假设我们想实现这么一种需求:

创建一个类Child,在这个类中定义的种种字符串属性,都可以当做对应的函数那样调用.例如:

class Child():

    f1='print'

随后,Child.f1就完全和内建函数print等价了.Child.f1('abc')能够打印出abc这个字符串.

这样来说,元类的用途看起来可以是:一些高手设计了一个在幕后做了很多工作的元类,另一些开发人员只需要简单地继承这个元类或者这个元类的子类,敲几个属性定义的代码,就能实现很多复杂的功能.django就是这样的.比如它的model.Models就充分利用了这种魔法.

下面从代码层面展示元类具体是怎么运作的:

class MyMeta(type):    
    def __new__(cls, name, parents, attrs):
        for k,v in locals().items():            
            if isinstance(v,dict):
                for k2,v2 in v.items():
                    print(k,'|',k2,'|',type(v2),'|',v2)
            else:
                print(k,'|',v)            
        return type.__new__(cls, name, parents, attrs)  

class Parent1(type):
    pass

class Parent2(object):
    pass

class Parent3():
    pass

class AbstractChild(Parent1,Parent2,Parent3,metaclass=MyMeta):
    pass

class Child(AbstractChild):
    
    f1 = 1
    f2 = sorted
    f3 = int
    
    class classinchild():
        pass

    @staticmethod
    def stcm():
        pass
    
    @classmethod
    def clsm(cls):
        pass
    
    def insm(self):
        pass

print('-'*60)

class EvalMeta(type):
    def __new__(cls, name, parents, attrs):
        new_attrs={}
        for k,v in attrs.items():            
            if not k.startswith('__') and isinstance(v,str):
                new_attrs[k] = eval(v)
            else:
                new_attrs[k] = v           
        return type.__new__(cls, name, parents, new_attrs)

class AbstractChild(metaclass=EvalMeta):
    pass

class Child(AbstractChild):
    f1='print'
    f2='sorted'

if __name__=='__main__':
    x=Child()
    x.f1('invoke f1 as print function')
    print('invoke f2 as sorted function:',Child.f2([3,2,1]))

结果:

>>> 
name | AbstractChild
cls | <class '__main__.MyMeta'>
parents | (<class '__main__.Parent1'>, <class '__main__.Parent2'>, <class '__main__.Parent3'>)
attrs | __module__ | <class 'str'> | __main__
attrs | __qualname__ | <class 'str'> | AbstractChild
name | Child
cls | <class '__main__.MyMeta'>
parents | (<class '__main__.AbstractChild'>,)
attrs | stcm | <class 'staticmethod'> | <staticmethod object at 0x0000000003075C50>
attrs | clsm | <class 'classmethod'> | <classmethod object at 0x000000000309CA58>
attrs | __module__ | <class 'str'> | __main__
attrs | insm | <class 'function'> | <function Child.insm at 0x0000000003139400>
attrs | __qualname__ | <class 'str'> | Child
attrs | f1 | <class 'int'> | 1
attrs | f3 | <class 'type'> | <class 'int'>
attrs | f2 | <class 'builtin_function_or_method'> | <built-in function sorted>
attrs | classinchild | <class 'type'> | <class '__main__.Child.classinchild'>
------------------------------------------------------------
invoke f1 as print function
invoke f2 as sorted function: [1, 2, 3]
>>> 
原文地址:https://www.cnblogs.com/xiangnan/p/3508441.html