为什么getattr()比self.__dict__.get()慢这么多?

11
下面的示例来自于Python 2.7上的REST数据库驱动程序。
在下面的`__setattr__`方法中,如果我使用注释掉的`getattr()`行,则将对象实例化性能从600 rps降至230.
在这种情况下为什么`getattr()`比`self.__dict__.get()`慢那么多?
class Element(object):

    def __init__(self, client):
        self._client = client
        self._data = {}
        self._initialized = True

    def __setattr__(self, key, value):
        #_initialized = getattr(self, "_initialized", False)
        _initialized = self.__dict__.get("_initialized", False)
        if key in self.__dict__ or _initialized is False:
            # set the attribute normally
            object.__setattr__(self, key, value)
        else:
            # set the attribute as a data property
            self._data[key] = value

2
顺便提一下,如果您遇到性能差异,请将self.__dict__缓存到本地变量中 - 即使只有两个访问。(在__setattr__的开始处使用dict_ = self.__dict__ - jsbueno
1个回答

13

简单来说,因为getattr(foo,bar)foo.bar做的是相同的事情,这与直接访问__dict__属性不同(首先,getattr必须选择正确的__dict__,但还有更多的操作)。

下面是一个例子:

>>> class A:
...   a = 1
...
>>> class B(A):
...   b = 2
...
>>> dir(B)
['__doc__', '__module__', 'a', 'b']
>>> B.a
1
>>> B.__dict__
{'__module__': '__main__', 'b': 2, '__doc__': None}
>>> B.__dict__['a']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'a'
>>> B.__dict__.get('a')
>>>

在此处包含或链接的详细信息:http://docs.python.org/reference/datamodel.html(搜索 "getattr")。


2
@bereal:你需要重新阅读一下。foo.dict.get()所需的操作是getattr()的一个适当子集。 - bukzor
2
请记住,Python字节码不对应原始操作。您可以使用非常少量的字节码调用非常复杂的函数,而一个简单的表达式可能会生成更多的字节码。此外,bukzor所说的是正确和相关的。 - Marcin
@bereal 这并不证明 foo.__dict__getattr(foo, '__dict__') 是一样的,因为调用 getattr(foo,'__dict__') 可能比解引用任意属性更有效率。 - Marcin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接