标签:style blog http color io os ar 使用 sp
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 ...
我们称这个对象为类对象,因为该对象可以实例化,创建实例对象,因此我们称它为类。
因为它是一个对象,所以:
比如
>>> 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>
其实,类对象也是实例化的结果,即类对象是由另一个类实例化得到的,我们称该类为元类,即元类是产生类的类,反之也成立,
如果类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 Foo True
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‘>
标签:style blog http color io os ar 使用 sp
原文地址:http://www.cnblogs.com/ajianbeyourself/p/4052084.html