类实例上元类的方法

时间:2010-02-11 06:37:40

标签: python metaclass

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

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print "foo"
... 
>>> a=A()
>>> a.foo()
foo
>>> A.foo()
foo

但是,如果我尝试定义一个元类并给它一个方法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'

这到底发生了什么?

编辑:提出问题

4 个答案:

答案 0 :(得分:15)

你提出了一个好点。

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

我还发现this reference on descriptors对于python中的查找机制非常有启发性。

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

编辑:

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

alt text http://www.cafepy.com/article/python_types_and_objects/images/types_map.png

原则上,它归结为:

A.foo

转到 left 意味着转到给定实例的类。 up 意味着转到

现在,继承机制使查找机制在上面的模式中进行右转。它是type -- object | | Meta -- A -- a 。它必须这样做才能遵循继承规则!为清楚起见,搜索路径为:

a → A → object

然后,很明显,找不到属性 object ^ | A <-- a

但是,当您在foo中查找属性foo时,找到了 ,因为查找路径为:

A

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

答案 1 :(得分:7)

规则是这样的:当在对象上搜索属性时,也会考虑对象的类及其父类。但是,对象的类的元类是。当您访问类的属性时,类的类是元类,因此。从对象到其类的回退不会触发对类的“正常”属性查找:例如,无论是在实例上还是在类上访问属性,都会以不同方式调用描述符。

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

答案 2 :(得分:0)

我理解的方式是Meta是一个类,A是它的一个实例。因此,当您调用A.foo()时,它会检查对象及其类。因此,在尝试A.foo时,它首先查看A本身持有的方法,然后查看其类的方法Meta。因为A本身没有方法foo,所以它使用Meta之一,因此真正执行Meta.foo(A)。

同样,当尝试a.foo时,它将首先查看a。作为一个没有方法foo,它将通过A看。但是A也没有方法foo,因为foo在Meta中保存。由于a和A都不包含foo,因此会引发AttributeError。

我用变量和函数尝试了这个,将Meta属性txt ='txt'放入类中,这也是A可以访问的,但不是a。所以,我倾向于认为我的理解是正确的,但我只是在猜测。

答案 3 :(得分:0)

接受的答案中的链接已经消失了,至少对我而言。所以我想补充一些东西:

3. Data model — object.__getattribute__

我认为有两个要点:

  • object.__getattribute__控制实例的属性访问。
  • type.__getattribute__控件类的属性访问。