Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > sum() requires number, not simply __add__

Reply
Thread Tools

sum() requires number, not simply __add__

 
 
Buck Golemon
Guest
Posts: n/a
 
      02-23-2012
I feel like the design of sum() is inconsistent with other language
features of python. Often python doesn't require a specific type, only
that the type implement certain methods.

Given a class that implements __add__ why should sum() not be able to
operate on that class?

We can fix this in a backward-compatible way, I believe.

Demonstration:
I'd expect these two error messages to be identical, but they are
not.

>>> class C(object): pass
>>> c = C()
>>> sum((c,c))

TypeError: unsupported operand type(s) for +: 'int' and 'C'
>>> c + c

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


 
Reply With Quote
 
 
 
 
Buck Golemon
Guest
Posts: n/a
 
      02-23-2012
On Feb 23, 1:19*pm, Buck Golemon <(E-Mail Removed)> wrote:
> I feel like the design of sum() is inconsistent with other language
> features of python. Often python doesn't require a specific type, only
> that the type implement certain methods.
>
> Given a class that implements __add__ why should sum() not be able to
> operate on that class?
>
> We can fix this in a backward-compatible way, I believe.
>
> Demonstration:
> * * I'd expect these two error messages to be identical, but they are
> not.
>
> * * *>>> class C(object): pass
> * * *>>> c = C()
> * * *>>> sum((c,c))
> * * TypeError: unsupported operand type(s) for +: 'int' and 'C'
> * * >>> c + c
> * * TypeError: unsupported operand type(s) for +: 'C' and 'C'


Proposal:

def sum(values,
base=0):
values =
iter(values)

try:
result = values.next()
except StopIteration:
return base

for value in values:
result += value
return result
 
Reply With Quote
 
 
 
 
Arnaud Delobelle
Guest
Posts: n/a
 
      02-23-2012
On 23 February 2012 21:19, Buck Golemon <(E-Mail Removed)> wrote:
> I feel like the design of sum() is inconsistent with other language
> features of python. Often python doesn't require a specific type, only
> that the type implement certain methods.
>
> Given a class that implements __add__ why should sum() not be able to
> operate on that class?


It can. You need to pass a second argument which will be the start
value. Try help(sum) for details.

--
Arnaud
 
Reply With Quote
 
Chris Rebert
Guest
Posts: n/a
 
      02-23-2012
On Thu, Feb 23, 2012 at 1:19 PM, Buck Golemon <(E-Mail Removed)> wrote:
> I feel like the design of sum() is inconsistent with other language
> features of python. Often python doesn't require a specific type, only
> that the type implement certain methods.
>
> Given a class that implements __add__ why should sum() not be able to
> operate on that class?


The time machine strikes again! sum() already can. You just need to
specify an appropriate initial value (the empty list in this example)
for the accumulator :

Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53)
[GCC 4.2.1 (Based on Apple Inc. build 565 (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> sum([[1,2],[3,4]], [])

[1, 2, 3, 4]

Cheers,
Chris
--
http://rebertia.com
 
Reply With Quote
 
Buck Golemon
Guest
Posts: n/a
 
      02-23-2012
On Feb 23, 1:32*pm, Chris Rebert <(E-Mail Removed)> wrote:
> On Thu, Feb 23, 2012 at 1:19 PM, Buck Golemon <(E-Mail Removed)> wrote:
> > I feel like the design of sum() is inconsistent with other language
> > features of python. Often python doesn't require a specific type, only
> > that the type implement certain methods.

>
> > Given a class that implements __add__ why should sum() not be able to
> > operate on that class?

>
> The time machine strikes again! sum() already can. You just need to
> specify an appropriate initial value (the empty list in this example)
> for the accumulator :
>
> Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53)
> [GCC 4.2.1 (Based on Apple Inc. build 565 (LLVM build 2335.15.00)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.>>>sum([[1,2],[3,4]], [])
>
> [1, 2, 3, 4]
>
> Cheers,
> Chris
> --http://rebertia.com


Thanks. I did not know that!

My proposal is still *slightly* superior in two ways:

1) It reduces the number of __add__ operations by one
2) The second argument isn't strictly necessary, if you don't mind
that the 'null sum' will produce zero.

def sum(values, base=0):
values = iter(values)

try:
result = values.next()
except StopIteration:
return base

for value in values:
result += value

return result
 
Reply With Quote
 
Arnaud Delobelle
Guest
Posts: n/a
 
      02-23-2012
On 23 February 2012 21:23, Buck Golemon <(E-Mail Removed)> wrote:
> def sum(values,
> base=0):
> * * *values =
> iter(values)
>
> * * *try:
> * * * * *result = values.next()
> * * *except StopIteration:
> * * * * *return base
>
> * * *for value in values:
> * * * * *result += value
> * * *return result


This is definitely not backward compatible. To get something that has
a better chance of working with existing code, try this (untested):

_sentinel = object()

def sum(iterable, start=_sentinel):
if start is _sentinel:
iterable = iter(iterable)
try:
start = iterable.next()
except StopIteration:
return 0
for x in iterable:
start += x
return start

del _sentinel

--
Arnaud
 
Reply With Quote
 
Stefan Behnel
Guest
Posts: n/a
 
      02-23-2012
Chris Rebert, 23.02.2012 22:32:
> On Thu, Feb 23, 2012 at 1:19 PM, Buck Golemon <(E-Mail Removed)> wrote:
>> I feel like the design of sum() is inconsistent with other language
>> features of python. Often python doesn't require a specific type, only
>> that the type implement certain methods.
>>
>> Given a class that implements __add__ why should sum() not be able to
>> operate on that class?

>
> The time machine strikes again! sum() already can. You just need to
> specify an appropriate initial value (the empty list in this example)
> for the accumulator :
>
> Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53)
> [GCC 4.2.1 (Based on Apple Inc. build 565 (LLVM build 2335.15.00)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
>>>> sum([[1,2],[3,4]], [])

> [1, 2, 3, 4]


I know that you just meant this as an example, but it's worth mentioning in
this context that it's not exactly efficient to "sum up" lists this way
because there is a lot of copying involved. Each adding of two lists
creates a third one and copies all elements into it. So it eats a lot of
time and space.

Stefan

 
Reply With Quote
 
Chris Angelico
Guest
Posts: n/a
 
      02-23-2012
On Fri, Feb 24, 2012 at 8:41 AM, Arnaud Delobelle <(E-Mail Removed)> wrote:
> _sentinel = object()
>
> def sum(iterable, start=_sentinel):
> * *if start is _sentinel:
>
> del _sentinel


Somewhat off-topic: Doesn't the if statement there do a lookup for a
global, which would mean that 'del _sentinel' will cause it to fail?
Or have I missed something here?

ChrisA
 
Reply With Quote
 
Ian Kelly
Guest
Posts: n/a
 
      02-23-2012
On Thu, Feb 23, 2012 at 2:38 PM, Buck Golemon <(E-Mail Removed)> wrote:
> My proposal is still *slightly* superior in two ways:
>
> 1) It reduces the number of __add__ operations by one
> 2) The second argument isn't strictly necessary, if you don't mind
> that the 'null sum' will produce zero.


It produces the wrong result, though:

>>> sum([3,4], base=12)

7

If I'm starting with 12 and summing 3 and 4, I expect to get 19.

Ideally the second argument should be ignored only if it isn't passed
in at all, and I don't know off-hand why the built-in sum doesn't do
this. We really don't need to replace it, though. If you want a
different sum behavior, just write your own.

def sum(iterable, *args):
return reduce(operator.add, iterable, *args)

>>> sum([3,4])

7
>>> sum([3,4], 12)

19
>>> sum(['hello', 'world'])

'helloworld'

Cheers,
Ian
 
Reply With Quote
 
Arnaud Delobelle
Guest
Posts: n/a
 
      02-23-2012
On 23 February 2012 21:53, Chris Angelico <(E-Mail Removed)> wrote:
> On Fri, Feb 24, 2012 at 8:41 AM, Arnaud Delobelle <(E-Mail Removed)> wrote:
>> _sentinel = object()
>>
>> def sum(iterable, start=_sentinel):
>> * *if start is _sentinel:
>>
>> del _sentinel

>
> Somewhat off-topic: Doesn't the if statement there do a lookup for a
> global, which would mean that 'del _sentinel' will cause it to fail?
> Or have I missed something here?


Yes, you're right Change the signature to

def sum(iterable, start=_sentinel, _sentinel=_sentinel):

This is not pretty...

--
Arnaud
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Don't work __getattr__ with __add__ Андрей Симурзин Python 2 03-04-2010 08:54 AM
proxy class and __add__ method Magnus Schuster Python 0 07-29-2008 04:13 PM
simply tag just not applying... :o shawnews HTML 2 11-24-2006 01:04 AM
Difference: __iadd__ and __add__ Ronny Mandal Python 3 02-18-2006 02:47 PM
ASP:Button on_click event simply will not ever fire Weston Weems ASP .Net 2 09-03-2004 06:14 PM



Advertisments