[Tutor] could somebody please explain...
Clayton Kirkwood
crk at godblessthe.us
Wed Oct 1 18:43:29 CEST 2014
!-----Original Message-----
!From: Tutor [mailto:tutor-bounces+crk=godblessthe.us at python.org] On
!Behalf Of Steven D'Aprano
!Sent: Tuesday, September 30, 2014 6:38 PM
!To: tutor at python.org
!Subject: Re: [Tutor] could somebody please explain...
!
!On Tue, Sep 30, 2014 at 03:54:42PM -0700, Clayton Kirkwood wrote:
!
!> I don't understand the multiplicity of some tools. Namely, why is
!> there a 'a+b', operator.add(a,b), operator.__add__(a,b),
!> operator.iadd(a,b),
!> operator.__iadd__(a,b) and their related operators?
!
!The + operator is the public interface, but the implementation that
!makes + work are the special methods __add__ and __radd__ .
!
!When you write in your code:
!
! result = a + b
!
!how does Python know what to do with a and b? In principle, Python could
!hard-code into the language a handful of types that the interpreter
!knows how to add: int, float, str, list, etc. But that is not easily
!extended when a new type is supported, and Python supports "operator
!overloading" where any custom class can define "a + b" to do whatever
!the class developer wants.
!
!So when the Python interpreter executes a + b, when it does is look for
!a special "dunder" (Double UNDERscore) method on a, __add__, or a
!special dunder method __radd__ ("right add") on b, and calls that.
!
!Actually the rules are a bit more complicated than that, which I'm happy
!to explain if you would like, but for simplicity let's ignore __radd__
!and just say that when Python sees "a + b" what actually gets called is
!a.__add__(b).
!
!So when you create a new class and want it to support the + operator,
!you write a __add__ method:
!
!class Spam:
! def __add__(self, other):
! ...
!
!
!and now Python knows how to add your Spam instances together.
!
!Sometimes it is useful to treat the + operator as a function, e.g. so
!that you can pass it to another function like reduce. But operators
!aren't values, you can't pass them to functions. This doesn't work:
!
!py> reduce(+, [1, 2, 3, 4])
! File "<stdin>", line 1
! reduce(+, [1, 2, 3, 4])
! ^
!SyntaxError: invalid syntax
!
!
!But you can wrap the operator in a function using lambda:
!
!py> reduce(lambda a, b: a+b, [1, 2, 3, 4])
!10
!
!
!but a more efficient way is to use the pre-made functions in the
!operator module:
!
!py> import operator
!py> reduce(operator.add, [1, 2, 3, 4])
!10
!
!
!So for every operator + - * / ** etc. there is a corresponding function
!version in the operator module, add(), sub() etc.
!
!
![ Aside: you might not know about reduce(). It takes a function f, and a
!list [a, b, c, d, ...] and calls the function with the first two values:
!
! result = f(a, b)
!
!then takes that result and repeatedly calls the function again with the
!next value from the list:
!
! result = f(result, c)
! result = f(result, d)
! ...
!
!until there are no more values left, then returns the final result.
!These days, now that Python has a sum() function, reduce() doesn't get
!used very often. ]
!
!So for each operator that Python knows about, there is the operator
!itself, a function version, and one or two special dunder methods:
!
! Operator Function Dunder methods
! ========== ============== =====================
! + operator.add __add__ __radd__
! - operator.sub __sub__ __rsub__
! * operator.mul __mul__ __rmul__
! ** operator.pow __pow__ __rpow__
! == operator.eq __eq__
! != operator.ne __ne__
!
!etc.
!
!Then there are the special "augmented assignment" operators, so that
!Python can support writing:
!
! x += 1
! y -= x
!
!etc. Again, the syntax used is a combined operator-assignment += and
!that ends up calling a special dunder method, __iadd__. And again, there
!are special function versions in the operator module.
!
!
!In summary:
!
!(1) When you want to add two values, use a + b.
!
!(2) When you want a function that adds two values, use operator.add.
!
!(3) When you want to write a class that supports addition, give it
! the two special dunder methods __add__ and __radd__.
!
!(4) You almost never should call __add__ yourself.
!
In an effort to learn and teach, I present a simple program which measures
the time it takes to the various add functions with the appending results:
# program to test time and count options
import datetime,operator, sys
from datetime import time, date, datetime
date = datetime.now()
dayofweek = date.strftime("%a, %b")
print("Today is", dayofweek, date.day, "at ", date.time())
start = 0
count_max=int(input("give me a number"))
start_time = datetime.now()
print( start_time )
while start < count_max:
start=start + 1
end_time = datetime.now()
print( "s=s+1 time difference is:", (end_time - start_time) )
start=0
start_time = datetime.now()
while( start < count_max ):
start += 1
end_time = datetime.now()
print( "the += time difference is:", (end_time - start_time) )
start_time = datetime.now()
start = 0
while( start < count_max ):
start = operator.add( start, 1)
end_time = datetime.now()
print( "the operator.add time difference is:", (end_time - start_time) )
start_time = datetime.now()
start=0
while( start < count_max ):
start = operator.iadd( start, 1)
end_time = datetime.now()
print( "the operator.iadd time difference is:", (end_time - start_time) )
start_time = datetime.now()
start=0
while( start < count_max ):
start = operator.__add__(start,1)
end_time = datetime.now()
print( "the operator.__add__ time difference is:", (end_time - start_time) )
start_time = datetime.now()
start=0
while( start < count_max ):
start = operator.__iadd__(start,1)
end_time = datetime.now()
print( "the operator.__iadd__ time difference is:", (end_time - start_time)
)
As can be seen below, there is a definite pattern: s=s+1 and s+=1, are
faster. There is some variability within the two schemes, but typically, the
iadds are slowest.
Today is Wed, Oct 1 at 09:19:05.671235
give me a number22222222
2014-10-01 09:19:18.485235
s=s+1 time difference is: 0:00:09.438000
the += time difference is: 0:00:09.072000
the operator.add time difference is: 0:00:17.172000
the operator.iadd time difference is: 0:00:17.325000
the operator.__add__ time difference is: 0:00:17.248000
the operator.__iadd__ time difference is: 0:00:17.673000
Today is Wed, Oct 1 at 09:35:06.525235
give me a number10000000
2014-10-01 09:35:17.915235
s=s+1 time difference is: 0:00:04.412000
the += time difference is: 0:00:04.343000
the operator.add time difference is: 0:00:07.499000
the operator.iadd time difference is: 0:00:07.734000
the operator.__add__ time difference is: 0:00:07.494000
the operator.__iadd__ time difference is: 0:00:07.906000
Today is Wed, Oct 1 at 09:39:07.830235
give me a number100000
2014-10-01 09:39:14.445235
s=s+1 time difference is: 0:00:00.042000
the += time difference is: 0:00:00.041000
the operator.add time difference is: 0:00:00.084000
the operator.iadd time difference is: 0:00:00.077000
the operator.__add__ time difference is: 0:00:00.076000
the operator.__iadd__ time difference is: 0:00:00.080000
Process finished with exit code 0
!
!
Clayton
!--
!Steven
!_______________________________________________
!Tutor maillist - Tutor at python.org
!To unsubscribe or change subscription options:
!https://mail.python.org/mailman/listinfo/tutor
More information about the Tutor
mailing list