类实例上元类的方法

Ste*_*ini 11 python metaclass

我想知道在元类上声明的方法会发生什么.我希望如果你在元类上声明一个方法,它最终将成为一个类方法,但是,行为是不同的.例

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print "foo"
... 
>>> a=A()
>>> a.foo()
foo
>>> A.foo()
foo
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试定义一个元类并给它一个方法foo,它似乎对类有效,而不是实例.

>>> class Meta(type): 
...     def foo(self): 
...         print "foo"
... 
>>> class A(object):
...     __metaclass__=Meta
...     def __init__(self):
...         print "hello"
... 
>>> 
>>> a=A()
hello
>>> A.foo()
foo
>>> a.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'foo'
Run Code Online (Sandbox Code Playgroud)

这到底发生了什么?

编辑:碰撞问题

Oli*_*ier 15

你提出了一个好点.

这是一个很好的参考,可以更好地理解对象,类和元类之间的关系:

我也发现这个关于描述符的引用对于 python中的查找机制非常有启发性.

但我不能说我理解为什么a.fooA.foo成功时失败.看起来,当你查找一个对象的属性,并且python在那里找不到它时,它并没有完全查找类中的属性,因为如果它确实,它会找到它A.foo.

编辑:

哦! 我想我明白了.这是由于继承如何工作.如果您考虑上述链接提供的架构,它看起来像这样:

替代文字http://www.cafepy.com/article/python_types_and_objects/images/types_map.png

原理上,它归结为:

type -- object
  |       |
Meta --   A  -- a
Run Code Online (Sandbox Code Playgroud)

手段要去类的指定实例.去手段去的家长.

现在,继承机制使查找机制在上面的模式中向右转.它去了a ? A ? object.它必须这样做才能遵循继承规则!为清楚起见,搜索路径是:

 object
   ^
   |
   A  <-- a
Run Code Online (Sandbox Code Playgroud)

然后,显然,foo将找不到该属性.

但是,当您查找属性fooA,找到它,因为查找路径是:

type
  ^
  |       
Meta <--   A 
Run Code Online (Sandbox Code Playgroud)

当人们想到继承如何运作时,这一切都是有道理的.


Tho*_*ers 9

规则是这样的:当在对象上搜索属性时,也考虑对象的类及其父类.但是,考虑对象的类的元类.当你访问一个类的属性,类的类是元类,所以它认为是.从对象到其类的回退不会触发对类的"正常"属性查找:例如,无论是在实例上还是在其类上访问属性,都会以不同方式调用描述符.

方法是可调用的属性(并且具有__get__使'self'自动传递的方法.)这使得如果在类上调用它们,但在实例上不可用,则元类上的方法就像classmethods.