I have the following code:
class MyClass:
def __init__(self):
self.some_variable = None
def func1(self):
i = 1
while i < 10:
yield i * i
self.some_variable = len(str((i * i)))
i += 1
def func2(self):
*_, last = my_class.func1()
print(self.some_variable)
my_class = MyClass()
my_class.func2()
As you can see, some_variable is the length of the last element in the generator. Basically, I was wondering, is this the most pythonic way of getting this variable? If not, how should this be done? I'm just wondering if this is how it should be done or if there's a better way of doing this.
Probably the simplest code is to simply use a for loop to consume the generator, doing nothing in the loop body. The loop variable will have the last value from the generator after the loop ends, which is exactly what you want.
for x in some_generator():
pass
print(x) # print the last value yielded by the generator
This may be a little more efficient than other options because it discards all the values before the last one, rather than storing them in a list or some other data structure.
I think that one pythonic way would be to yield both the element and the length:
def func1():
i = 1
while i < 10:
yield i * i, len(str((i * i)))
i += 1
def func2():
*_, (_, last_len) = func1()
print(last_len)
func2()
or even to extract the calculation of the derived value to another function and call it after consuming the generator:
def func1():
i = 1
while i < 10:
yield i * i
i += 1
def func2(i):
return len(str(i))
def func3():
*_, last = func1()
print(func2(last))
func3()
I think that you have simplified your example too much to be able to find the solution that fits your real use case the best.
How can I define a function in python in such a way that it takes the previous value of my iteration where I define the initial value.
My function is defined as following:
def Deulab(c, yh1, a, b):
Deulab = c- (EULab(c, yh1, a, b)-1)*0.3
return (Deulab,yh1, a,b)
Output is
Deulab(1.01, 1, 4, 2)
0.9964391705626454
Now I want to iterate keeping yh1, a ,b fixed and start with c0=1 and iterate recursively for c.
The most pythonic way of doing this is to define an interating generator:
def iterates(f,x):
while True:
yield x
x = f(x)
#test:
def f(x):
return 3.2*x*(1-x)
orbit = iterates(f,0.1)
for _ in range(10):
print(next(orbit))
Output:
0.1
0.2880000000000001
0.6561792000000002
0.7219457839595519
0.6423682207442558
0.7351401271107676
0.6230691859914625
0.7515327214700762
0.5975401280955426
0.7695549549155365
You can use the generator until some stop criterion is met. For example, in fixed-point iteration you might iterate until two successive iterates are within some tolerance of each other. The generator itself will go on forever, so when you use it you need to make sure that your code doesn't go into an infinite loop (e.g. don't simply assume convergence).
It sound like you are after recursion.
Here is a basic example
def f(x):
x += 1
if x < 10:
x = f(x)
return x
print (f(4))
In this example a function calls itself until a criteria is met.
CodeCupboard has supplied an example which should fit your needs.
This is a bit of a more persistent version of that, which would allow you to go back to where you were with multiple separate function calls
class classA:
#Declare initial values for class variables here
fooResult = 0 #Say, taking 0 as an initial value, not unreasonable!
def myFoo1(x):
y = 2*x + fooResult #A simple example function
classA.fooResult = y #This line is updating that class variable, so next time you come in, you'll be using it as part of calc'ing y
return y #and this will return the calculation back up to wherever you called it from
#Example call
rtn = classA.myFoo1(5)
#rtn1 will be 10, as this is the first call to the function, so the class variable had initial state of 0
#Example call2
rtn2 = classA.myFoo1(3)
#rtn2 will be 16, as the class variable had a state of 10 when you called classA.myFoo1()
So if you were working with a dataset where you didn't know what the second call would be (i.e. the 3 in call2 above was unknown), then you can revisit the function without having to worry about handling the data retention in your top level code. Useful for a niche case.
Of course, you could use it as per:
list1 = [1,2,3,4,5]
for i in list1:
rtn = classA.myFoo1(i)
Which would give you a final rtn value of 30 when you exit the for loop.
Is it possible to create a iterator/generator which will decide on the next value based on some result on the previous iteration?
i.e.
y = None
for x in some_iterator(ll, y):
y = some_calculation_on(x)
I would like the logic of choosing the next x to depend on the calculation result allowing different logic for different results, much like in a search problem.
I also want to keep the how to choose the next x and the calculation on x as separate as possible.
Did you that you can send to a generator using generator.send? So yes, you can have a generator to change its behaviour based on feedback from the outside world. From the doc:
generator.send(value)
Resumes the execution and “sends” a value into the generator function.
The value argument becomes the result of the current yield expression.
The send() method returns the next value yielded by the generator
[...]
Example
Here is a counter that will increment only if told to do so.
def conditionalCounter(start=0):
while True:
should_increment = yield start
if should_increment:
start += 1
Usage
Since iteration with a for-loop does not allow to use generator.send, you have to use a while-loop.
import random
def some_calculation_on(value):
return random.choice([True, False])
g = conditionalCounter()
last_value = next(g)
while last_value < 5:
last_value = g.send(some_calculation_on(last_value))
print(last_value)
Output
0
0
1
2
3
3
4
4
5
Make it work in a for-loop
You can make the above work in a for-loop by crafting a YieldReceive class.
class YieldReceive:
stop_iteration = object()
def __init__(self, gen):
self.gen = gen
self.next = next(gen, self.stop_iteration)
def __iter__(self):
return self
def __next__(self):
if self.next is self.stop_iteration:
raise StopIteration
else:
return self.next
def send(self, value):
try:
self.next = self.gen.send(value)
except StopIteration:
self.next = self.stop_iteration
Usage
it = YieldReceive(...)
for x in it:
# Do stuff
it.send(some_result)
It's possible but confusing. If you want to keep the sequence of x values and the calculations on x separate, you should do this explicitly by not involving x with an iterator.
def next_value(x):
"""Custom iterator"""
# Bunch of code defining a new x
yield new_x
x = None
while True:
x = next_value(x)
x = some_calculation_on(x)
# Break when you're done
if finished and done:
break
If you want the loop to execute exactly i times, then use a for loop:
for step in range(i):
x = next_value(x)
x = some_calculation_on(x)
# No break
def conditional_iterator(y):
# stuff to create new values
yield x if (expression involving y) else another_x
for x in conditional_iterator(y):
y = some_computation(x)
So i'm trying to make a function that keeps track how many times a method is called.
for example:
a = [1,2,3,4]
a.pop()
i want to know how many times a.pop() was called so far so for this example, i would get 1.
Is there a way to do this?
This doesn't work for builtin functions, but an interesting approach would be:
def myfunction():
myfunction.counter += 1
myfunction.counter = 0
You're giving the function an attribute, so every call that attribute is updated. No global variables needed.
Built-ins are read-only. They cannot be modified.
You could use a decorator that tracks how many times the function is called. Since list is a built-in, you can't decorate or replace its pop method so you'd have to use your own list class, for example.
def counted(f):
def wrapped(*args, **kwargs):
wrapped.calls += 1
return f(*args, **kwargs)
wrapped.calls = 0
return wrapped
class MyList(list):
#counted
def pop(self, *args, **kwargs):
return list.pop(self, *args, **kwargs)
x = MyList([1, 2, 3, 4, 5])
for i in range(3):
x.pop()
print x.pop.calls # prints 3
i used the following little trick to track how many times the function was called
def myfun(s,i=[0]):
print(s)
i[0]+=1 # mutable variable get evaluated ONCE
return i[0]
>>> myfun('aaa')
aaa
1
>>> myfun('bbb')
bbb
2
Here is a simple and elegant solution for a self counting function, without any decorators, global variables, etc:
def hello():
hello.counter += 1
print(hello.counter)
hello.counter = 0
Each time you call hello(), it will print 1, 2, etc.
Let's not forget that, in Python, a function is a first-class citizen
and it has rights. And one of them is to have attributes!
If you are willing to include your method call in a function, it can be easy:
def pop_counted(a):
pop_counted.counter += 1
return a.pop()
pop_counted.counter = 0
Voilà!
Comment
This works because a Python function "knows" itself (this is a necessary feature, so that functions can call themselves recursively if desired).
If you wish to keep some information about a function, it might be better to keep it where it belongs: in an attribute of the function.
The advantage of not using a global variable is scope:
no risk of name collisions in the global namespace
the information you were keeping will vanish as soon as the function is taken off the stack, which is what you want -- no garbage left.
A bonus is that this approach will work in cases where a global variable is not really a good option, typically for nested functions where you can't declare a "global" in the outer function.
For kicks, I wrote up an answer using a decorator:
class counter:
#wraps a function, to keep a running count of how many
#times it's been called
def __init__(self, func):
self.func = func
self.count = count
def __call__(self, *args, **kwargs):
self.count += 1
return self.func(*args, **kwargs)
To use it, simply decorate a function. You can then check how many times that function has been run by examining the "count" attribute. Doing it this way is nice because:
1.) No global variables. The count is associated directly with the function.
2.) You can wrap builtin functions easily, by calling the class directly:
sum_wrapped = counter(sum)
sum_wrapped([1, 2 ,3, 4])
#outputs 10
print sum_wrapped.count
#outputs 1
Of course, this could be improved by using the Decorators module to keep the docstrings and other good things intact. Also, for an excellent overview of what decorators are, and how they work, check out this stackoverflow answer.
One approach is to create a proxy of the instance for which you want to count attribute access:
from collections import Counter
class CountingProxy():
def __init__(self, instance):
self._instance = instance
self.count = Counter()
def __getattr__(self, key):
if hasattr(self._instance, key):
self.count[key] += 1
return getattr(self._instance, key)
>>> l = [1,2,3,4,5]
>>> cl = CountingProxy(l)
>>> cl.pop()
5
>>> cl.append(10)
>>> cl.index(3)
2
>>> cl.reverse()
>>> cl.reverse()
>>> cl.count
Counter({'reverse': 2, 'pop': 1, 'append': 1, 'index': 1})
A simple way to do this is to increment a global variable each time you call the function.
counter = 0
a = [1,2,3,4]
a.pop()
counter += 1
i guess the following code will be helpful to you. you just need to make local variable global in order to access the global variable from a method
MYGLOBAL = 5
def func1():
global MYGLOBAL
MYGLOBAL +=10
def func2():
print (MYGLOBAL)
func1() #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func1() #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func1() #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func2() #this will printout 5+30=35
counter = 0
def pop():
counter += 1
print counter
#other function code
a = [1,2,3,4]
a.pop()
this should solve your issue and you should be able to see whats being counted. +
every time you call the function the counter is going to be increased and printed with every pass of the function.
IF ITS BUILT IN:
counter = 0
def newfunction():
a = [1,2,3,4]
a.pop()
counter += 1
print counter
the logic in this is that it will call your new function go into the function that is premade then step out of the built in function and then go on to mark the counter as increased. the output your counter.
Just define a global statement in your function.
count = 1
def your_func():
global count
print(count)
count= count +1
Just define a global variable and increment it inside function.
a = 0
def some_function():
global a
a+=1
<..Your code.>
This will automatically be incremented as function is used and you can access it globally.
I did it copying the way JavaScript console.count() method works. That's my code:
class Terminal(object):
__count_names = []
def count(self, name='default'):
# check if name already exists
i = next((self.__count_names.index(item) for item in self.__count_names if item['name'] == name), None)
# if name argument does not exist register it
if i is None:
dictionary = { 'name': name, 'count': 1 }
self.__count_names.append(dictionary)
# if exists increment 'count'
else:
dictionary = self.__count_names[i]
dictionary['count'] += 1
self.__count_names[i] = dictionary
# finally print name and count
print(f"{dictionary['name']} : {dictionary['count']}")
Your code should look like this:
terminal = Terminal()
def myFunc():
terminal.count("myFunc")
myFunc()
myFunc()
myFunc("myFunc")
Output:
myFunc: 1
myFunc: 2
myFunc: 3
myFunc: 4
An example from Datacamp, using decorators:
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count += 1
# Call the function being decorated and return the result
return func(*args, **kwargs)
wrapper.count = 0
# Return the new decorated function
return wrapper
# Decorate foo() with the counter() decorator
#counter
def foo():
print('calling foo()')
foo()
foo()
print('foo() was called {} times.'.format(foo.count))
# output
calling foo()
calling foo()
foo() was called 2 times.
I solve this with closure. This is a generic function:
def counter(fn):
cnt=0
def inner(*args,**kwargs):
nonlocal cnt
cnt+=1
print('{0} has been called {1} times'.format(fn.__name__,cnt))
return fn(*args,**kwargs)
return inner
a=[1,2,3,4]
a_pop=counter(a.pop)