Python3 五分钟理解元类(Metaclasses)
|
五分钟理解元类(Metaclasses) 真的,它并非巫术。
原文地址:http://www.voidspace.org.uk/python/articles/five-minutes.shtml 日期:16 September,2008. 译者:赖勇浩(http://blog.csdn.net/lanphaday) ?“元类的魔幻变化比?99%?的用户所担心的更多,当你搞不懂是否真的需要用它的时候,就是不需要。” —Tim Peters 本文源于在?PyCon UK 2008?上的一个快速演讲。 元类被称为?Python?中的“深奥的巫术”。尽管你需要用到它的地方极少(除非你基于?zope?编程),可事实上它的基础理论其实令人惊讶地易懂。 一切皆对象
以前,术语?type?用于内置类型,而术语?class?用于用户定义的类,但自?Pythoon 2.2?以来“class”和“type”本质上并无不同。 对于旧风格(old-style)类的类型是?types.ClassType。 真的,这是真的 Python?2.5.1(r251:54869,Apr182007,128);">22:08:04) 从这里可以看出在交互式解释器中创建的类是一个?first class?的对象。 类的类是…… 它的元类…… 就像对象是类的实例一样,类是它的元类的实例。 调用元类可以创建类。 确切来说,Python?中的其它对象也是如此。 因此当你创建一个类时…… 解释器会调用元类来生成它…… 定义一个继承自?object?的普通类意味着调用来创建它: >>> help(type) Help on class type in module __builtin__: ? class type(object) ?|??type(object) -> the object's type ?|??type(name,bases,dict) -> a new type type?的第二种用法尤为重要。当解释器在执行一条类定义语句时(如例子中最初的两行代码之后),它会用下面的参数调用?type:
简单模拟 def__init__self?????.message='Hello World'say_helloprintattrs{'__init__':,0);">'say_hello'}basesHello'Hello'basesattrs'__main__.Hello'hHello()h 以上代码创建了类属性的字典,然后调用来创建了名为?Hello?的类。 __Metaclass__?的魔法 只要在类定义中把?__Metaclass__?设置为任意有着与相同参数的可调用对象,就能够提供自定义的元类。 通常使用从继承的方法: PointlessMetaclass 重要的是在?__new__?方法中我们能够读取或改变传入的用以创建新类的参数。从而能够内省属性字典和改动、增加或者删除成员。 尽管当实例化一个类时这两个函数都会被调用,但覆盖比?__init__?更为重要。__init__?初始化一个实例,而的职责是创建它。因此如果元类用以自定义类的创建,就需要覆盖的?__new__。 使用新类而非仅仅提供工厂函数的原因在于如果使用工厂函数(那样只是调用)的话元类不会被继承。 In Action... WhizzBang__Metaclass__PointlessMetaclassWhizzBang'__main__.WhizzBang''__main__.PointlessMetaClass'WhizzBang?是一个类,但它现在已经不是的实例,而是我们自定义的元类的实例了…… 这有什么用? 很好的问题,元类将用在创建使用了它的新类时调用,这里是一些关于这样做的好处的观点:
最重要之处在于元类中是在最后对的调用时才真正创建类,所以可以自由地随你喜欢地改变属性字典(以及名称和元组形式的基类序列)。 一些流行的?Python ORM(Object Relational Mappers(对象关系影射),用以和数据库协同工作)也如此使用元类。 哦,还有因为元类是继承的,所以你能够提供一个使用了你的元类的基类,而继承自它的子类就无需显式声明它了。 但是…… 我曾未需要使用它来编写代码……(我们用它来剖分,也在?Ironclad?项目广泛应用它,但我不编写这些)。 还有,这一切只适用于?Python 2.x,其中的机制在?Python 3?中已经改变了。 type(type) is type 在?Python 2.6?中现在也可用使用??class decorators?来实现许多以前可能需要用元类来实现的东西。 最后,还有一个极尽奇技淫巧的例子(稍为深入,但仍然不难消化),可以去看看?The Selfless Metaclass。它通过字节码和方法签名重写来避免显式地声明?self? |


