defreduce(f,*args):ifnot(1<=len(args)<=2):# if undecodedable argumentsiflen(args)<1:raise TypeError('reduce expected at least 2 arguments, got '+str(len(args)))else:raise TypeError('reduce expected at most 3 arguments, got '+str(len(args)))
iterable = args[0]
i =iter(iterable)# create iteratortry:# try (to handle empty iterator if no unit)
a = args[1]iflen(args)==2elsenext(i)# use unit or get first valuewhileTrue:# while (to process more values in iterator)try:# try (to determine if more values)
a = f(a,next(i))# get next/f combines with previous resultexcept StopIteration:# when no more values in iteratorreturn a # return reduced/accumulated resultexcept StopIteration:# empty iterator (with no unit): raise exceptionraise TypeError('reduce() of empty sequence with no initial value')fromNone
Note that
reduce(operator.add,[]) raises a TypeError Exception
TypeError:reduce() of empty sequence with no initial value
reduce(operator.add,[],0) returns 0(the unit)reduce(operator.add,[5]) returns 5reduce(operator.add,[5],0) returns 5(the unit,0,+ the first value)reduce(operator.add,[5],5) returns 10(the unit,5,+ the first value)
Note the "from None"in the last line. If we raise an exception while handling
an exception in Python, both exceptions appear in the trace. But the TypeError
exception is what we want to communicate (the StopIteration exception was just
how we know there is a problem) so by including "from None" it instructs Python
to remove the StopIteration exception from the trace.
def reduce(f,*args): if not (1 <= len(args) <= 2): # if undecodedable arguments if len(args) < 1: raise TypeError('reduce expected at least 2 arguments, got '+str(len(args))) else: raise TypeError('reduc