为什么 sum() 没有关键参数?

Why sum() does not have the key arg?

今天,我自动写了一些这样的东西:

class Foo():
    def __init__(self, x):
        self.x = x

s = [Foo(1), Foo(2), Foo(3)]
sum_x = sum(s, key = lambda foo: foo.x)

得到这个:

TypeError: sum() takes no keyword arguments

sum() 没有 key arg 有什么特殊原因吗?

因为您可以只写 sum(foo.x for foo in s)。如果您尝试使用带有 key 参数(sortedminmax 等)的函数之一执行此操作,该函数最终会返回键而不是原始项目,并且在按键排序时获取原始项目非常棘手,以至于 Python 为您提供了一种通过关键字参数执行此操作的内置方法。

因此:sum 没有特殊原因不参加 key;相反,那些其他函数有特殊原因 do 需要 keykey 是例外,不是规则。

没有 key 参数,因为 sum() 没有 return 原始元素(如 sorted()min()max()做)。相反,它只是对输入求和。

如果,比方说,min() 没有采用 key 参数,它就不能 return 基于属性的最小 Foo() 对象;它只能 return 该属性的值。但是 sum() 不是这样的,它不需要保留原始对象。

您可以轻松地转换生成器表达式中的输入:

sum(item.x for item in s)

虽然没有 key 参数,但好消息是您 可以 使用 sum 用你的 Foo 对象!其他人已经指出,最简单的方法是 这样做

sum(item.x for item in s)

不过,不理解也可以使用。

添加对象

为了求和,需要先进行基本加法运算。

In [2]: class Foo:
...:     def __init__(self, x):
...:         self.x = x
...:

In [3]: Foo(3) + Foo(5)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-f0e9c3a4abb9> in <module>()
----> 1 Foo(3) + Foo(5)

TypeError: unsupported operand type(s) for +: 'Foo' and 'Foo'

我们可以通过定义 __add__ 方法来启用加法。

In [4]: class Foo:
...:     def __init__(self, x):
...:         self.x = x
...:     def __add__(self, other):
...:         return Foo(self.x + other.x)
...:

In [5]: Foo(3) + Foo(5)
Out[5]: <__main__.Foo at 0x102bdc2e8>

表明它有效

In [6]: result = Foo(3) + Foo(5)

In [7]: result.x
Out[7]: 8

但这并不能解决所有问题。

In [8]: sum([Foo(3), Foo(5)])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-70968119f3ba> in <module>()
----> 1 sum([Foo(3), Foo(5)])

TypeError: unsupported operand type(s) for +: 'int' and 'Foo'

我们没有尝试添加 int,但 sum 函数认为我们添加了。给出了什么?

sum 函数

使用ipython检查sum函数,你可以看到它包括一个 可选 start 参数

In [1]: sum??
Docstring:
sum(iterable[, start]) -> value

Return the sum of an iterable of numbers (NOT strings) plus the value
of parameter 'start' (which defaults to 0).  When the iterable is
empty, return start.
Type:      builtin_function_or_method

因此,sum(s)sum(s, 0) 相同,就是这个开始 导致错误的值。我们所要做的就是替换起始值 与等效的 Foo 对象

In [9]: sum([Foo(3), Foo(5)], Foo(0))
Out[9]: <__main__.Foo at 0x102bdc9e8>

In [10]: result = sum([Foo(3), Foo(5)], Foo(0))

In [11]: result.x
Out[11]: 8

这也适用于其他一些类型

In [12]: sum([[1,2,3], [4,5,6]], [])
Out[12]: [1, 2, 3, 4, 5, 6]

但不是全部

In [13]: sum(["abc", "def"], "")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-452a33de0457> in <module>()
----> 1 sum(["abc", "def"], "")

TypeError: sum() can't sum strings [use ''.join(seq) instead]