两句话掌握 Python 最难知识点——元类出处( 七 )

  • class MetaSingleton(type):
  • instance = None
  • def __call__(cls, *args, **kw):
  • """
  • this is comment
  • """
  • print 'in call method'
  • if cls.instance is None:
  • # cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
  • # cls.instance = type.__dict__['__call__'].__get__(cls)(*args, **kw)
  • cls.instance = type.__call__(cls, *args, **kw)
  • print cls.instance
  • return cls.instance
  • class Foo(object):
  • __metaclass__ = MetaSingleton
  • def __init__(self, a, b):
  • self.a = a
  • self.b = b
  • a = Foo(1, 2)
  • b = Foo(3, 4)
  • assert a is b
  • print a.a, a.b, b.a, b.b
  • print type(Foo)
  • print Foo.__call__
  • 例子很直接,__call__方法里面通过判断是否已经有初始化过的实例,没有就仿照正常未指定元类的情况下调用type的__call__方法(当然这里要么通过super binding要么手动指定cls上下文),生成一个Foo的实例存储和返回出来 。但是有一个注意点是,call方法每次初始化实例对象的时候都会被调用,这也和先前说的控制实例的生成一致:
  • Python
  • (<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
  • in call method
  • <__main__.Foo object at 0x00000000024BFA90>
  • in call method
  • <__main__.Foo object at 0x00000000024BFA90>
  • 1 2 1 2
  • <class '__main__.MetaSingleton'>
  • <bound method MetaSingleton.__call__ of <class '__main__.Foo'>>
  • 还有一个需要在意的地方是最后的两行打印日志,Foo类型的元类是Metasingleton(调用new生成类型的时候默认指定元类是第一个参数);Foo的__call__方法是绑定了Foo(MetaSingleton的实例)实例的MetaSingleton的方法,也就是从另外的方面证实每次初始化Foo类型市里的时候,其实是在调用元类中重写的__call__方法 。
  • 元类这个特性大多数情况下确实使用的不多并且需要稍微花点时间来理解,但是需要使用的时候会非常好用,往往能够实现很多优雅的功能,最典型的就是ORM的实现了,只不过会更加的复杂,且pythoning且学习吧,PEACE!
  • 参考资料中的链接里面有有几个实际的例子,本文也是学习其中的内容后配合一些其它一些使用经验以及碰到的问题理而成,希望对大家有用 。

  • 【两句话掌握 Python 最难知识点——元类出处】


    推荐阅读