我想知道在元类上声明的方法会发生什么。我希望如果你在元类上声明一个方法,它最终将成为一个类方法,但是,行为是不同的。实施例
>>> 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'
这到底发生了什么?
编辑:提出问题
答案 0 :(得分:15)
你提出了一个好点。
这是一个good reference,可以更好地理解对象,类和元类之间的关系:
我还发现this reference on descriptors对于python中的查找机制非常有启发性。
但我不能说我明白为什么a.foo
在A.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__
控件类的属性访问。