python - 为什么 python 不利用 __iadd__ 求和和链式运算符?

标签 python optimization python-internals

我刚刚进行了一个有趣的测试:

~$ python3 # I also conducted this on python 2.7.6, with the same result
Python 3.4.0 (default, Apr 11 2014, 13:05:11) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(object):
...     def __add__(self, other):
...         global add_calls
...         add_calls += 1
...         return Foo()
...     def __iadd__(self, other):
...         return self
...
>>> add_calls = 0
>>> a = list(map(lambda x:Foo(), range(6)))
>>> a[0] + a[1] + a[2]
<__main__.Foo object at 0x7fb588e6c400>
>>> add_calls
2
>>> add_calls = 0
>>> sum(a, Foo())
<__main__.Foo object at 0x7fb588e6c4a8>
>>> add_calls
6

很明显,__iadd__ 方法比__add__ 方法更高效,不需要分配新的类。如果我添加的对象足够复杂,这将创建不必要的新对象,可能会在我的代码中造成巨大的瓶颈。

我希望,在 a[0] + a[1] + a[2] 中,第一个操作将调用 __add__,第二个操作将调用将在新创建的对象上调用 __iadd__

为什么python不优化这个?

最佳答案

__add__ 方法可以自由返回不同类型的对象,而 __iadd__ 如果使用就地语义,应该返回 self .它们在这里不需要返回相同类型的对象,因此 sum() 不应依赖于 __iadd__ 的特殊语义。

您可以使用 functools.reduce() function自己实现所需的功能:

from functools import reduce

sum_with_inplace_semantics = reduce(Foo.__iadd__, a, Foo())

演示:

>>> from functools import reduce
>>> class Foo(object):
...     def __add__(self, other):
...         global add_calls
...         add_calls += 1
...         return Foo()
...     def __iadd__(self, other):
...         global iadd_calls
...         iadd_calls += 1
...         return self
... 
>>> a = [Foo() for _ in range(6)]
>>> result = Foo()
>>> add_calls = iadd_calls = 0
>>> reduce(Foo.__iadd__, a, result) is result
True
>>> add_calls, iadd_calls
(0, 6)

关于python - 为什么 python 不利用 __iadd__ 求和和链式运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31054393/

相关文章:

python - 什么是 _PyEval_EvalFrameDefault?

python - 像 dict.fromkeys 这样的内置类型的函数描述符与普通方法的行为不同

python - 条件检查序列

python - 从循环中创建值列表

c - DCRaw 说我应该在 gcc 中使用 -O4 进行编译。 -O4存在吗?

database-design - 如何优化这些数据的访问?

python - 如何使用 python 从 url 导入 ics 文件

python - 与 native pymongo 使用相比,Mongoengine 在大型文档上非常慢

java - 如何优化寻找特定对象?

python - 在元组上调用元组时的元组身份