Why sum() does not have the key arg?

两盒软妹~` 提交于 2020-02-25 03:15:47

问题


Today, I automatically wrote some thing like this:

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)

And got this:

TypeError: sum() takes no keyword arguments

Is there any special reason for sum() does not have a key arg?


回答1:


Because you can just write sum(foo.x for foo in s) instead. If you tried to do this with one of the functions that does take a key argument (sorted, min, max, etc.), the function would end up returning the key(s) rather than the original item(s), and getting the original items while sorting by keys is tricky enough that Python gives you a built-in way to do that via a keyword argument.

Thus: There's no special reason for sum to not take a key; rather, those other functions have special reasons why they do take a key. key is the exception, not the rule.




回答2:


There is no key argument because sum() doesn't return the original elements (like sorted(), min() and max() do). Instead, it just sums the inputs.

If, say, min() did not take a key argument, it could not return the minimum Foo() object based on an attribute; it could only return the value of that attribute. But sum() doesn't work that way, it doesn't need to preserve the original objects.

You can easily transform the inputs in a generator expression:

sum(item.x for item in s)



回答3:


Although there is no key param, the good news is that You can use sum with your Foo object! Others have already pointed out that the easiest way to do this

sum(item.x for item in s)

However, it's also possible to use it without the comprehension.

Object addition

In order for sum to work, basic addition needs to work first.

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'

We can enable addition by defining the __add__ method.

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>

to make clear that it worked

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

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

But this doesn't solve everything.

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'

We didn't try to add an int, but the sum function thinks we did. What gives?

THE sum FUNCTION

using ipython to inspect the sum function, you can see that it includes an optional start parameter

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

So according to that, sum(s) is the same as sum(s, 0) and it's this start value that is causing the error. All we have to do is replace the start value with the equivalent Foo object

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

This also applies to some other types

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

but not all of them

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]


来源:https://stackoverflow.com/questions/31574541/why-sum-does-not-have-the-key-arg

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!