Making an addition accumulator in python [duplicate] - python

This question already has answers here:
How to find the cumulative sum of numbers in a list?
(25 answers)
Closed 8 years ago.
What is desired is to
def accumulator():
def addition():
something here
and others
return addition
where
A = accumulator()
A(10)
10
A(10)
20
using Message Passing such that every accumulator() will have the overall sum at the end.
I have no idea how to start. . . I would be really appreciative if you could help!
Thanks

Just another variant, with closures.
def accumulator():
sum = 0
def addition(n):
nonlocal sum
sum += n
return sum
return addition

You could define a coroutine, as Aशwini चhaudhary suggested:
def coroutine(func):
"""
http://www.python.org/dev/peps/pep-0342/
http://www.dabeaz.com/coroutines/index.html
"""
def wrapper(*args, **kw):
gen = func(*args, **kw)
gen.send(None)
return gen
return wrapper
#coroutine
def accumulator():
val = 0
while True:
val += (yield val)
which can be used like this:
A = accumulator().send
print(A(10))
# 10
print(A(10))
# 20
print(A(10))
# 30

Not sure if this is what you are asking, but you can get the desired effect by updating a class variable.
class accumulator(object):
summation = 0
def __call__(self,val):
accumulator.summation+=val
print accumulator.summation
A = accumulator()
A(10)
A(10)
B = accumulator()
B(10)
B(100)
This will give:
10
20
30
130
and every instance will have the correct value in the summation attribute.
If you want to keep the summations of A and B separate:
class accumulator(object):
def __init__(self):
self.summation = 0
def __call__(self,val):
self.summation+=val
print self.summation

Related

How exactly works this Python generator example? [duplicate]

How would one create an iterative function (or iterator object) in python?
Iterator objects in python conform to the iterator protocol, which basically means they provide two methods: __iter__() and __next__().
The __iter__ returns the iterator object and is implicitly called
at the start of loops.
The __next__() method returns the next value and is implicitly called at each loop increment. This method raises a StopIteration exception when there are no more value to return, which is implicitly captured by looping constructs to stop iterating.
Here's a simple example of a counter:
class Counter:
def __init__(self, low, high):
self.current = low - 1
self.high = high
def __iter__(self):
return self
def __next__(self): # Python 2: def next(self)
self.current += 1
if self.current < self.high:
return self.current
raise StopIteration
for c in Counter(3, 9):
print(c)
This will print:
3
4
5
6
7
8
This is easier to write using a generator, as covered in a previous answer:
def counter(low, high):
current = low
while current < high:
yield current
current += 1
for c in counter(3, 9):
print(c)
The printed output will be the same. Under the hood, the generator object supports the iterator protocol and does something roughly similar to the class Counter.
David Mertz's article, Iterators and Simple Generators, is a pretty good introduction.
There are four ways to build an iterative function:
create a generator (uses the yield keyword)
use a generator expression (genexp)
create an iterator (defines __iter__ and __next__ (or next in Python 2.x))
create a class that Python can iterate over on its own (defines __getitem__)
Examples:
# generator
def uc_gen(text):
for char in text.upper():
yield char
# generator expression
def uc_genexp(text):
return (char for char in text.upper())
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text.upper()
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text.upper()
def __getitem__(self, index):
return self.text[index]
To see all four methods in action:
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print(ch, end=' ')
print()
Which results in:
A B C D E
A B C D E
A B C D E
A B C D E
Note:
The two generator types (uc_gen and uc_genexp) cannot be reversed(); the plain iterator (uc_iter) would need the __reversed__ magic method (which, according to the docs, must return a new iterator, but returning self works (at least in CPython)); and the getitem iteratable (uc_getitem) must have the __len__ magic method:
# for uc_iter we add __reversed__ and update __next__
def __reversed__(self):
self.index = -1
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += -1 if self.index < 0 else +1
return result
# for uc_getitem
def __len__(self)
return len(self.text)
To answer Colonel Panic's secondary question about an infinite lazily evaluated iterator, here are those examples, using each of the four methods above:
# generator
def even_gen():
result = 0
while True:
yield result
result += 2
# generator expression
def even_genexp():
return (num for num in even_gen()) # or even_iter or even_getitem
# not much value under these circumstances
# iterator protocol
class even_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
# getitem method
class even_getitem():
def __getitem__(self, index):
return index * 2
import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
limit = random.randint(15, 30)
count = 0
for even in iterator():
print even,
count += 1
if count >= limit:
break
print
Which results in (at least for my sample run):
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
How to choose which one to use? This is mostly a matter of taste. The two methods I see most often are generators and the iterator protocol, as well as a hybrid (__iter__ returning a generator).
Generator expressions are useful for replacing list comprehensions (they are lazy and so can save on resources).
If one needs compatibility with earlier Python 2.x versions use __getitem__.
I see some of you doing return self in __iter__. I just wanted to note that __iter__ itself can be a generator (thus removing the need for __next__ and raising StopIteration exceptions)
class range:
def __init__(self,a,b):
self.a = a
self.b = b
def __iter__(self):
i = self.a
while i < self.b:
yield i
i+=1
Of course here one might as well directly make a generator, but for more complex classes it can be useful.
First of all the itertools module is incredibly useful for all sorts of cases in which an iterator would be useful, but here is all you need to create an iterator in python:
yield
Isn't that cool? Yield can be used to replace a normal return in a function. It returns the object just the same, but instead of destroying state and exiting, it saves state for when you want to execute the next iteration. Here is an example of it in action pulled directly from the itertools function list:
def count(n=0):
while True:
yield n
n += 1
As stated in the functions description (it's the count() function from the itertools module...) , it produces an iterator that returns consecutive integers starting with n.
Generator expressions are a whole other can of worms (awesome worms!). They may be used in place of a List Comprehension to save memory (list comprehensions create a list in memory that is destroyed after use if not assigned to a variable, but generator expressions can create a Generator Object... which is a fancy way of saying Iterator). Here is an example of a generator expression definition:
gen = (n for n in xrange(0,11))
This is very similar to our iterator definition above except the full range is predetermined to be between 0 and 10.
I just found xrange() (suprised I hadn't seen it before...) and added it to the above example. xrange() is an iterable version of range() which has the advantage of not prebuilding the list. It would be very useful if you had a giant corpus of data to iterate over and only had so much memory to do it in.
This question is about iterable objects, not about iterators. In Python, sequences are iterable too so one way to make an iterable class is to make it behave like a sequence, i.e. give it __getitem__ and __len__ methods. I have tested this on Python 2 and 3.
class CustomRange:
def __init__(self, low, high):
self.low = low
self.high = high
def __getitem__(self, item):
if item >= len(self):
raise IndexError("CustomRange index out of range")
return self.low + item
def __len__(self):
return self.high - self.low
cr = CustomRange(0, 10)
for i in cr:
print(i)
If you looking for something short and simple, maybe it will be enough for you:
class A(object):
def __init__(self, l):
self.data = l
def __iter__(self):
return iter(self.data)
example of usage:
In [3]: a = A([2,3,4])
In [4]: [i for i in a]
Out[4]: [2, 3, 4]
All answers on this page are really great for a complex object. But for those containing builtin iterable types as attributes, like str, list, set or dict, or any implementation of collections.Iterable, you can omit certain things in your class.
class Test(object):
def __init__(self, string):
self.string = string
def __iter__(self):
# since your string is already iterable
return (ch for ch in self.string)
# or simply
return self.string.__iter__()
# also
return iter(self.string)
It can be used like:
for x in Test("abcde"):
print(x)
# prints
# a
# b
# c
# d
# e
Include the following code in your class code.
def __iter__(self):
for x in self.iterable:
yield x
Make sure that you replace self.iterablewith the iterable which you iterate through.
Here's an example code
class someClass:
def __init__(self,list):
self.list = list
def __iter__(self):
for x in self.list:
yield x
var = someClass([1,2,3,4,5])
for num in var:
print(num)
Output
1
2
3
4
5
Note: Since strings are also iterable, they can also be used as an argument for the class
foo = someClass("Python")
for x in foo:
print(x)
Output
P
y
t
h
o
n
This is an iterable function without yield. It make use of the iter function and a closure which keeps it's state in a mutable (list) in the enclosing scope for python 2.
def count(low, high):
counter = [0]
def tmp():
val = low + counter[0]
if val < high:
counter[0] += 1
return val
return None
return iter(tmp, None)
For Python 3, closure state is kept in an immutable in the enclosing scope and nonlocal is used in local scope to update the state variable.
def count(low, high):
counter = 0
def tmp():
nonlocal counter
val = low + counter
if val < high:
counter += 1
return val
return None
return iter(tmp, None)
Test;
for i in count(1,10):
print(i)
1
2
3
4
5
6
7
8
9
class uc_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
Improving previous answer, one of the advantage of using class is that you can add __call__ to return self.value or even next_value.
class uc_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
def __call__(self):
next_value = self.value
self.value += 2
return next_value
c = uc_iter()
print([c() for _ in range(10)])
print([next(c) for _ in range(5)])
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# [20, 22, 24, 26, 28]
Other example of a class based on Python Random that can be both called and iterated could be seen on my implementation here

Pass a variable that increases as it is called?

How can I do this in python?
a = 0
func(a+=1) # a = 1
func(a+=1) # a = 2
Now I have had to solve it like this:
a = 0
a+=1
func(a)
a+=1
func(a)
...
and there must be a better way, right?
Edit:
Actually I also want to be able to pass it to different functions:
a = 0
a+=1
func1(a)
a+=1
func2(a)
a+=1
func1(a)
...
your solution is okay, but if you want to have a counting side effect, use itertools.count object:
import itertools
def f(x):
print(x)
c = itertools.count()
f(next(c))
f(next(c))
or the variant, performing the next call in the functions themselves (itertools.counter is mutable so you can modify it inside the function):
import itertools
def f(c):
x = next(c)
print(x)
c = itertools.count()
f(c)
f(c)
you can initialize it to a non-zero value: c = itertools.count(3)
Something simple like this:
a = 0
a+=1;func1(a)
a+=1;func2(a)
Each line is only 2 characters longer than your original request.
You can have a wrapping function that calls your function f and simultaneously increment the value of j!
>>> def f(a):print("Value of a is: %d"%a)
...
>>> c=lambda i:(i+1,f(i+1))
>>> j=0
>>> j,_=c(j)
Value of a is: 1
>>> j
1
>>> j,_=c(j)
Value of a is: 2
>>> j
2
There is no way in the sense that in Python, assignment is an instruction, not an operator whose operation returns a value.
You'll have to define a function and either use the global keyword with a or turn a into a mutable. You can also use a decorator for your functions.
a = [0]
#a = 0 # alternative version
def inc(x):
x[0] += 1
return x[0]
# global a # alternative version
# a += 1
# return a
def f1(x):
return x + 1
def f2(x):
return x + 2
# or (inspired by #jpp comment) decorate your functions
def inc1(x):
def inner(x):
x[0] += 1
return x[0]
return inner
#inc1
def f3(x):
return x
for i in range(10):
print(inc(a))
print()
print(f1(inc(a)))
print(f2(inc(a)))
print()
a = [0]
print(f3(a))
print(f3(a))

relay multiple keyword arguments from outer function to inner functions in Python?

I am trying to pass arguments to an outer function that then relays them to one or more inner functions. The closest I've come to achieving this:
def multiply(number, factor=1):
return number*factor
def add(number, to_add=0):
return number+to_add
def multiply_add(number, *args):
return add(multiply(number, *args[0]), *args[1])
multiply_add(5, [3], [200])
Out[]: 215
This solution is impractical in a few ways: 1) The user has to know the order in which to pass the arguments, without using keywords; and 2) These arguments have to be iterables for some reason, otherwise get "TypeError: multiply() argument after * must be an iterable, not int".
My question: how to rewrite multiply_add() so the following works? :
multiply_add(5, factor=3, to_add=200)
P.S. I've seen a working example of this with Seaborn calling additional Matplotlib arguments. For example, making the dot size equal to 25:
sns.jointplot(x='A', y='B', data=df, kind='reg', scatter_kws={'s': 25})
Something in this form would be great too.
Ok, I figured out how to do this offline. There are at least two ways.
FIRST WAY: slap **kwargs absolutely everywhere
def multiply(number, factor=1, **kwargs):
return number*factor
def add(number, to_add=0, **kwargs):
return number+to_add
def multiply_add(number, **kwargs):
return add(multiply(number, **kwargs), **kwargs)
multiply_add(5, to_add=200, factor=3)
Note that argument order doesn't matter here.
SECOND WAY: specify different sets of **kwargs and pass them in dict form (my preferred)
def multiply(number, factor=1):
return number*factor
def add(number, to_add=0):
return number+to_add
def multiply_add(number, kwargs_multiply, kwargs_add):
return add(multiply(number, **kwargs_multiply), **kwargs_add)
multiply_add(5, {'factor':3}, {'to_add':200})
Note that argument order DOES matter here: the multiply() arguments need to be specified before the add() arguments.
This is not much beautiful code, but I think it does what you want right ?
1 def multiply(number, factor=1.0):
2 return number*factor
3
4 def add(number, to_add=0):
5 return number+to_add
6
7 def multiply_add(number, **kwargs):
8 factor = kwargs.get("factor")
9 to_add = kwargs.get("to_add")
11 if to_add and factor:
12 return add(multiply(number, factor), to_add)
13 elif to_add:
14 return add(multiply(number), to_add)
15 elif factor:
16 return add(multiply(number, factor))
Maybe you prefer:
1 def multiply(number, factor=1.0):
2 if factor == None:
3 factor=1.0
4 return number*factor
5
6 def add(number, to_add=0):
7 if to_add == None:
8 to_add=0
9 return number+to_add
10
11 def multiply_add(number, **kwargs):
12 factor = kwargs.get("factor")
13 to_add = kwargs.get("to_add")
14 return add(multiply(number, factor), to_add)
15 print multiply_add(30)
16 print multiply_add(30, to_add=2)
17 print multiply_add(30, to_add=25)
18 print multiply_add(30, factor=8)
19 print multiply_add(30, factor=2, to_add=6)
These answers didn't help me much, but I was looking for something else anyway. Since I've figured it out, I thought I might post the answer here, for someone who may get here the same way I did.
In my case I wanted an outer function that would take my inner function as an argument and my inner function would have other arguments, but the inner function along with it's arguments could be different every time.
Granted the solution I found is so easy, probably everyone knows it.
So my outer function times the one time execution of the inner function and print out a pretty output:
def timeFun(function):
t_start = perf_counter()
print("---\nResult: ", function, "\nExecution time: ", perf_counter() - t_start, sep="")
Now for the sake of simplicity my inner function is such, that it's pointless to time it:
def sumTogether(*args):
return sum(args)
Now you simply call the function like this:
timeFun(sumTogether(1, 2, 3, 4))
And the output is:
---
Result: 10
Execution time: 7.99999999995249e-07
Also:
def time(function):
t_start = perf_counter()
print("---\nResult: ", function, "\nExecution time: ", perf_counter() - t_start, sep="")
def sumTogether(*args, just_for_kicks=5):
return sum(args) + just_for_kicks
time(sumTogether(1, 2, 3, 4, just_for_kicks=10))
Output:
---
Result: 20
Execution time: 8.999999999981245e-07

How to compose a list of functions to a callable [duplicate]

This question already has answers here:
Composing functions in python
(16 answers)
Closed 5 years ago.
I have a simple source.
def h(x):
return x + 1
def m(x):
return x + 2
def n(x):
return x * 10
def function_aggregator(fun_list, num):
return_fun = None
for fun in fun_list[::-1]:
if return_fun:
return_fun = fun(return_fun)
else:
return_fun = fun(num)
return return_fun
if __name__ == "__main__":
lst = [h, m, n]
y = function_aggregator(lst, 4)
print(y)
Is there any way to make the function_aggregator method receive just the list and return a callable the will be the same as h(m(n(<any_number>))
The previous answer is pretty close. The exact answer is:
def function_aggregator(fun_list):
def wrapper(arg):
for fun in reversed(fun_list):
arg = fun(arg)
return arg
return wrapper
if __name__ == "__main__":
lst = [g, f, n, m, h]
p = function_aggregator(lst)
x = 3
print("p(x): {}".format(p(x)))
Thanks to Zero Piraeus commet
It could be done using closure:
def function_aggregator(*func_list):
def aggregate(num):
for func in reversed(func_list):
num = func(num)
return num
return aggregate
if __name__ == "__main__":
myfunc = function_aggregator(h, m, n)
print(myfunc(4))
Notes
function_aggregator now takes an arbitrary number of functions
Inside, it defines another function, aggregate, this is the callable you are talking about.
function_aggregator returns that callable, AKA aggregate to the caller
The caller then give it a name, myfunc in this case
From then on, we can treat myfunc as a function which takes 1 argument and return something

create dynamic functions keeping state

Python beginner question. Say you want to dynamically create a function that keeps some state (in the code below an integer i). Then as the function defined is an object, we could use it later on. In the following code, I add the functions to a list, and each call to print(fn(0)) should result in 0 1 2 3 4, but instead I get 4 4 4 4 4 as if only the latest value of i is used.
fns = []
for i in range(5):
def fn(x):
return x + i
fns += [fn]
print(fns)
for fn in fns:
print(fn(0))
quit()
Is it possible to accomplish in Python what this code tries to do?
To work around the late binding issue, you can use default keyword parameter:
for i in range(5):
def fn(x, i=i): # <-----
return x + i
....
A function that retains its own state? I would do it like this:
class func:
# can behave as a function, but can also hold its own value
def __init__(self, value=0):
self.value = value
# this function is the actual 'function' that is called each time
def __call__(self, arg):
self.value += arg
return self.value
fns = []
for i in range(5):
# create new function, and give it a starting value of i
fn = func(i)
fns += [fn]
for fn in fns:
print( fn(0) )
The result is 0 1 2 3 4

Categories

Resources