python - 为什么@property 比属性慢,而字节码是相同的

标签 python performance properties cpython python-internals

考虑这段代码:

import timeit
import dis

class Bob(object):
    __slots__ = "_a",

    def __init__(self):
        self._a = "a"

    @property
    def a_prop(self):
        return self._a

bob = Bob()

def return_attribute():
    return bob._a

def return_property():
    return bob.a_prop

print(dis.dis(return_attribute))
print(dis.dis(return_property))

print("attribute:")
print(timeit.timeit("return_attribute()",
                    setup="from __main__ import return_attribute", number=1000000))
print("@property:")
print(timeit.timeit("return_property()",
                    setup="from __main__ import return_property", number=1000000))

很容易看出 return_attributereturn_property 产生相同的字节码:

 17           0 LOAD_GLOBAL              0 (bob)
              3 LOAD_ATTR                1 (_a)
              6 RETURN_VALUE        
None
 20           0 LOAD_GLOBAL              0 (bob)
              3 LOAD_ATTR                1 (a_prop)
              6 RETURN_VALUE        
None

但是,时间不同:

attribute:
0.106526851654
@property:
0.210631132126

为什么?

最佳答案

属性作为函数调用 执行,而属性查找仅仅是哈希表(字典)查找。所以是的,那总是会更慢。

LOAD_ATTR 字节码在这里不是定时操作。您缺少的是 LOAD_ATTR 将属性查找委托(delegate)给对象类型;通过触发 C 代码:

property 对象是数据描述符;它不仅实现了 __get__,还实现了 __set____delete__ 方法。使用实例在 property 上调用 __get__ 会导致 property 对象调用已注册的 getter 函数。

参见 Descriptor HOWTO有关描述符的更多信息,以及 Invoking Descriptors section Python 数据模型文档。

字节码没有区别,因为它不是由LOAD_ATTR 字节码来决定属性是属性还是常规属性。 Python 是一种动态语言,编译器不能事先知道访问的属性是否是一个属性。您可以随时更改您的类(class):

class Foo:
    def __init__(self):
        self.bar = 42

f = Foo()
print(f.bar)  # 42

Foo.bar = property(lambda self: 81)
print(f.bar)  # 81

在上面的示例中,当您从 bar 名称开始时,该名称仅作为 Foo 类的 f 实例的属性存在,通过添加 Foo.bar property 对象,我们拦截了名称 bar 的查找过程,因为 property 是一个数据描述符,因此可以覆盖任何实例查找。 但 Python 无法提前知道这一点,因此无法为属性查找提供不同的字节码。例如,Foo.bar 赋值可能发生在完全不相关的模块中。

关于python - 为什么@property 比属性慢,而字节码是相同的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57055758/

相关文章:

python终止/杀死子进程组

arrays - 如何将自定义属性添加到PowerShell数组?

php - 我们可以通过一些代码强制清除浏览器缓存吗

javascript - JavaScript 定时器会影响带宽吗

matlab - 如何在不显示的情况下编辑保存在 .fig 文件中的图形的属性

class - TEdit和TQuery

python - 使用 GoogleNews-vectors-negative300.bin 构建字典返回 ValueError : could not convert string to float

python - 动画弹丸轨迹 Python

python - 无法在 Pygame 中加载音乐

sql - 使用不同计数时如何提高性能