避免Python sum默认启动参数行为
我正在使用一个Python对象,它实现了避免Python sum默认启动参数行为,python,sum,Python,Sum,我正在使用一个Python对象,它实现了\uuuuu add\uuuuu,但没有子类intMyObj1+MyObj2工作正常,但是sum([MyObj1,MyObj2])导致了类型错误,因为sum()第一次尝试0+MyObj。为了使用sum(),我的对象需要处理MyObj+0或我需要提供一个空对象作为开始参数。所讨论的对象不是设计为空的 在任何人询问之前,对象不是类似列表或字符串的,因此使用join()或itertools不会有帮助 编辑以获取详细信息:模块有一个SimpleLocation和一
\uuuuu add\uuuuu
,但没有子类int
MyObj1+MyObj2
工作正常,但是sum([MyObj1,MyObj2])
导致了类型错误
,因为sum()
第一次尝试0+MyObj
。为了使用sum()
,我的对象需要处理MyObj+0
或我需要提供一个空对象作为开始
参数。所讨论的对象不是设计为空的
在任何人询问之前,对象不是类似列表或字符串的,因此使用join()或itertools不会有帮助
编辑以获取详细信息:模块有一个SimpleLocation和一个CompoundLocation。我将把地点缩写为Loc。SimpleLoc
包含一个右开区间,即[start,end]。添加SimpleLoc
将生成一个CompoundLoc
,其中包含区间列表,例如[[3,6],[10,13)]
。最终使用包括通过联合进行迭代,例如[3,4,5,10,11,12]
,检查长度和成员资格
数字可以相对较大(例如,小于2^32,但通常为2^20)。间隔可能不会很长(100-2000,但可能更长)。目前,只存储端点。我现在暂时考虑尝试将set
子类化,以便将位置构造为set(xrange(start,end))
。但是,添加集合将使Python(和数学家)适合
我看到的问题有:
我正在考虑两种解决方案。一种是避免sum()
并使用本文提供的循环。我不明白为什么sum()
首先将iterable的第0项添加到0,而不是添加第0项和第1项(如链接注释中的循环);我希望这是一个神秘的整数优化原因
我的另一个解决方案如下;虽然我不喜欢硬编码的零检查,但这是我唯一能够使sum()
工作的方法
# ...
def __radd__(self, other):
# This allows sum() to work (the default start value is zero)
if other == 0:
return self
return self.__add__(other)
总之,对于既不能添加到整数也不能为空的对象,是否有另一种方法使用sum()
呢?我认为实现这一点的最佳方法是提供\u radd\u
方法,或者将start对象显式传递给sum
如果您确实不想覆盖\uuu radd\uuu
或提供一个开始对象,那么重新定义sum()
怎么样
最好使用名为my_sum()
的函数,但我想这是您想要避免的事情之一(即使全局重新定义内置函数可能是未来的维护人员会诅咒您的事情)实际上,实现\uuuu add\uu
时没有“空对象”的概念没有什么意义。sum
需要一个start
参数来支持空序列和单元素序列的总和,并且您必须决定在这些情况下预期的结果:
sum([o1, o2]) => o1 + o2 # obviously
sum([o1]) => o1 # But how should __add__ be called here? Not at all?
sum([]) => ? # What now?
不要使用
sum
,而是使用:
import operator
from functools import reduce
reduce(operator.add, seq)
Python 2中内置了reduce
,因此如下所示:
import operator
reduce(operator.add, seq)
Reduce通常比sum更灵活-您可以提供任何二进制函数,不仅是add
,还可以选择提供初始元素,而sum
始终使用一个
另请注意:(警告:前面有数学咆哮) 从代数的角度来看,为没有中性元素的w/r/t对象提供
add
w/r/t支持有点笨拙
请注意:
- 自然的
- 雷亚尔
- 复数
- N-d向量
- NxM矩阵
- 弦
sum
一起很好地工作
在这种情况下,您最好使用函数或方法而不是运算符。这可能会减少混淆,因为您的类的用户看到它支持+
,可能会期望它将以单向方式运行(就像加法通常所做的那样)
感谢您的扩展,我现在将参考您的特定模块: 这里有两个概念:
- 位置简单
- 大院的位置
sum
,如下所示:
sum( [SimpleLoc1, SimpleLoc2, SimpleLoc3], start=ComplexLoc() )
事实上,这一点很重要
我现在暂时考虑尝试对set进行子类化,以便将位置构造为set(xrange(start,end))。但是,添加set将使Python(和数学家)适合 嗯,位置是一些数字集,因此在它们上面抛出一个类似集合的接口是有意义的(因此
\uuuuu包含
,\uuuuu iter\uuuuu
,\uuu len\uuuuu
,可能\uuuuu或
作为+/code>的别名,\uuuu和
作为产品,等等)
至于从xrange
构造,你真的需要它吗?如果你知道你正在存储区间集,那么你可能会通过坚持使用[开始,结束)
对来节省空间
sum( [SimpleLoc1, SimpleLoc2, SimpleLoc3], start=ComplexLoc() )
from operator import add
try:
total = reduce(add, whatever) # or functools.reduce in Py3.x
except TypeError as e:
# I'm not 100% happy about branching on the exception text, but
# figure this msg isn't likely to be changed after so long...
if e.args[0] == 'reduce() of empty sequence with no initial value':
pass # do something appropriate here if necessary
else:
pass # Most likely that + isn't usable between objects...
class Neutral:
def __add__(self, other):
return other
print(sum("A BC D EFG".split(), Neutral())) # ABCDEFG