最近读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] >>>