__getattr __,newstyle vs oldstyle类的不对称行为

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了__getattr __,newstyle vs oldstyle类的不对称行为相关的知识,希望对你有一定的参考价值。

这是我第一次写这篇文章,对不起,如果邮件没有被批评或太长。

我有兴趣了解更多关于如何在需要时获取对象的属性。所以我阅读了标题为“数据模型”here的Python 2.7文档,我遇到了__getattr__,为了检查我是否理解了它的行为,我编写了这些简单(和不完整)的字符串包装器。

class OldStr:
  def __init__(self,val):
    self.field=val

  def __getattr__(self,name):
    print "method __getattr__, attribute requested "+name

class NewStr(object):
  def __init__(self,val):  
    self.field=val

  def __getattr__(self,name):
    print "method __getattr__, attribute requested "+name

正如你所看到的那样,除了作为旧式和新式的课程外,它们是相同的。由于引用文本说__getattr__是“当一个属性查找没有找到通常位置的属性时调用”,我想在这些类的两个实例上尝试+操作,看看发生了什么,期待相同的行为。

但结果让我感到困惑:

>>> x=OldStr("test")
>>> x+x
method __getattr__, attribute requested __coerce__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

好!我没有为__coerce__定义一个方法(虽然我期待__add__,nevermind :)的请求,所以__getattr__介入并返回了一个无用的东西。但是之后

>>> y=NewStr("test")
>>> y+y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NewStr' and 'NewStr'

为什么在使用像+这样的内置运算符时,旧式班级和新式班级的__getattr__之间存在这种不对称行为?有人可以帮我理解发生了什么,以及我在阅读文档时的错误是什么?

非常感谢,非常感谢您的帮助!

答案

Special method lookup for new-style classes

在类对象中直接查找特殊方法,实例对象因此绕过__getattr__()__getattribute__()。出于同样的原因,instance.__add__ = foobar不起作用。

这样做是为了加速属性访问。特殊方法被非常频繁地调用,并且使它们受到标准的,相当复杂的属性查找的影响,这将大大减慢解释器的速度。

旧式类的属性查找要复杂得多(最明显的是旧式类不支持描述符),因此没有理由在旧式类中以不同方式处理特殊方法。

另一答案

你的__getattr__函数没有返回任何东西。我不知道为什么老式班级在寻找__getattr__之前正在做__add__,但事实并非如此,而这正试图将返回值称为None

新式的类正在做对:你没有定义__add__所以它不知道如何添加它们。

另一答案

Python文档中的更多信息:

http://docs.python.org/reference/datamodel.html#customizing-attribute-access

以上是关于__getattr __,newstyle vs oldstyle类的不对称行为的主要内容,如果未能解决你的问题,请参考以下文章

递归的原因是什么?

python之 __getattr____getattr____getitem____setitem__ 使用

python __getattr__

__getattr__,settr

python 类中__getattr__的使用

Python的__getattr__和__getattribute__