为什么python不使用__iadd__作为求和和链接运算符? [英] Why doesn't python take advantage of __iadd__ for sum and chained operators?

查看:129
本文介绍了为什么python不使用__iadd__作为求和和链接运算符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I just conducted an interesting test:

~$ 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__方法更有效,不需要分配新的类.如果添加的对象非常复杂,这将创建不必要的新对象,从而可能在我的代码中造成巨大的瓶颈.

Obviously, the __iadd__ method is more efficient than the __add__ method, not requiring the allocation of a new class. If my objects being added were sufficiently complicated, this would create unnecessary new objects, potentially creating huge bottlenecks in my code.

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

I would expect that, in an a[0] + a[1] + a[2], the first operation would call __add__, and the second operation would call __iadd__ on the newly created object.

为什么python无法对此进行优化?

Why doesn't python optimize this?

推荐答案

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

The __add__ method is free to return a different type of object, while __iadd__ should, if using in-place semantics, return self. They are not required to return the same type of object here, so sum() should not rely on the special semantics of __iadd__.

您可以使用 functools.reduce()函数来实现您自己想要的功能:

You can use the functools.reduce() function to implement your desired functionality yourself:

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不使用__iadd__作为求和和链接运算符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆