12

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

>>> 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

4 回答 4

16

你提出了一个很好的观点。

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

我还发现这个关于描述符的参考对python 中的查找机制非常有启发性。

但我不能说我明白为什么成功a.foo时会失败A.foo。似乎当您查找对象的属性时,python 没有在那里找到它,它并没有完全查找类中的属性,因为如果找到了,它会找到A.foo.

编辑:

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

替代文字

从原理上讲,它归结为:

type -- object
  |       |
Meta --   A  -- a

向左意味着去给定实例的类。上去意味着去父母那里

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

 object
   ^
   |
   A  <-- a

然后,很明显,foo将找不到该属性。

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

type
  ^
  |       
Meta <--   A 

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

于 2010-02-11T16:43:33.700 回答
9

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

方法是可调用的属性(并且具有__get__使“self”自动传递的方法。)这使得元类上的方法就像在类上调用它们时的类方法一样,但在实例上不可用。

于 2010-02-11T06:43:02.170 回答
0

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

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

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

于 2010-02-14T04:34:29.940 回答
0

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

3.数据模型——object.__getattribute__

并给出我认为的两个关键点:

  • object.__getattribute__控制实例的属性访问。
  • type.__getattribute__控制类的属性访问。
于 2019-06-15T07:43:59.530 回答