首页 > 代码库 > Python中的元类(译)
Python中的元类(译)
add by zhj: 这是大stackoverflow上一位小白提出的问题,好吧,我承认我也是小白,元类这块我也是好多次想搞明白,
但终究因为太难懂而败下阵来。看了这篇文章明白了许多,再加下啄木鸟社区的 Python 类型和对象 这篇文章。卧槽,
这简直就是珠联璧合,日月神剑啊,尼玛。终于干掉了元类。翻译时有修改,建议与原文一起看。
原文:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python?answertab=votes#tab-top
类是对象
在理解元类之前,你需要先掌握Python中的类。在Python中,对类的定义比较特殊,这点借鉴了Smalltalk语言。在大多
数语言中,类只是用于描述如何创建对象的代码片,在Python中,在一定程度上也是这样:
>>> class ObjectCreator(object):... pass... >>> my_object = ObjectCreator()>>> print(my_object)<__main__.ObjectCreator object at 0x8974f2c>
不过,Python中的类不止如此。类也是对象,是的,我没说错。
当你使用关键字class时,Python解释器执行时,会创建一个对象。如下,Python会在内存中创建一个对象,并在符号表
中增加一个标识符ObjectCreator,指向那个对象,这就是Python中所说的引用,我们也常称之为变量。
>>> class ObjectCreator(object):... pass...
我们称这个对象为类对象,因为该对象可以实例化,创建实例对象,因此我们称它为类。
因为它是一个对象,所以:
- 可以将它赋给一个变量
- 可以copy它
- 可以给它增加属性
- 可以将它作为函数参数
比如
>>> print(ObjectCreator) # 可以print it<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>
通过type类动态创建类
其实,类对象也是实例化的结果,即类对象是由另一个类实例化得到的,我们称该类为元类,即元类是产生类的类,反之也成立,
如果类X实例化后得到是类对象,那X就是元类。在Python中,只有type类及其子类才可以当元类。多说一句,这里会有鸡生蛋、
蛋生鸡的问题。在Python中,一切都是对象,一切对象都是类实例化的结果。对象由类实例化得到,而类也是对象,它也是由类(元类)
实例化得到,继续向上,元类也是对象,也要由另一个元类实例化得到,这样下去就没有尽头了。在Python中,这个追溯终止在type类。
元类是type类或其子类,而type类的元类就是它自己,哈哈,type类自己创建自己,牛逼吧,当然type类的这个特性是Python设计者
guido van rossum等人设计并实现的。至于Python解释器是怎么找到元类的,后面我们会讲。
还记得type()方法吗?我们常用它看一个对象X所属的类,即创建该对象X的类,当对象X是类对象时,看到的就是元类。如下,
>>> print(type(1))<type ‘int‘>>>> print(type("1"))<type ‘str‘>>>> print(type(ObjectCreator)) #查看创建ObjectCreator类的类<type ‘type‘>>>> print(type(ObjectCreator()))<class ‘__main__.ObjectCreator‘>
type类还有另外一个功能,它可以创建类,将类的一些信息做为type()的参数,并返回一个类。我知道,type根据输入参数的不同而有不同的功能,
这种做法是愚蠢的。当type()只有一个参数时,它的功能就是返回创建该参数对象的类;当多于一个参数时,type()才是type类的实例化,实例化得到
一个类并返回该类。type创建类时,参数格式如下,classname是类名,字符串类型,parentclasses是类所有父类,元组类型,attrs是类的所有{属性:值},
字典类型。
type(classname, parentclasses , attrs)
比如,
>>> class MyShinyClass(object):... pass
当解释器执行时,会转为下面的语句,当然,你也可以直接这么写。
MyShinyClass = type(‘MyShinyClass‘, (object,), {})
下面我们来定义一个类,并在类中定义属性,如
>>> class Foo(object):... bar = True
它会被翻译成下面的形式,
>>> 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
我们可以用另一个类继承它,so:
>>> class FooChild(Foo):... pass
would be:
>>> FooChild = type(‘FooChild‘, (Foo,), {})>>> print(FooChild)<class ‘__main__.FooChild‘>>>> print(FooChild.bar) # bar is inherited from FooTrue
OK,你会想给你的类增加方法。定义一个函数,并将它分配给类的属性
>>> 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创建类都是这么简单吗?都是直接用type元类实例化得到?
不是的,你可以指定元类,这就是__metaclass__属性。
什么是元类
元类就是创建类的类(话说作者说话够罗嗦的,当然,对于小白来说,多说几次才能看明白)
在上面,我们提到可以使用type()查看创建一个对象的类,你也可以使用__class__,如下
>>> 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__是什么呢?__class__返回的是一个类对象,再一次__class__返回的就是元类,如下
,下面这个结论并不具备普适性,有些类的元类并非元类。当然,如果你一直调用__class__,在有限次之后,
它返回的就一直是type类了。
>>> age.__class__.__class__<type ‘type‘>>>> name.__class__.__class__<type ‘type‘>>>> foo.__class__.__class__<type ‘type‘>>>> b.__class__.__class__<type ‘type‘>
什么是元类
Python中的元类(译)