I want to create an iterator that counts the length of another iterator while consuming it.
Here is a working example of what I want to achieve:
from random import random
def randleniter(p):
while random() < p:
yield 7
count = 0
def do():
def countiter(piter):
global count
for i in piter:
count += 1
yield i
list(countiter(randiter(0.99))) #simulator for a different method consuming the iterator
return count
>>> do()
81
However, I would have never built it like this if I intended to use a global variable. I imagined that since I can do this with nested methods:
def make_adder(x):
def add(y):
return x + y
return add
I would be able to do this:
def do():
count = 0
def countiter(piter):
for i in piter:
count += 1
yield i
list(countiter(randiter(0.99)))
return count
but this results in a UnboundLocalError: local variable 'count' referenced before assignment. When I print locals() from inside the countiter - it doesn't include count.
Can I make countiter access count somehow?
what you are describing is known as a closure, which is a topic completely independant from iterators and generators.
Python3.x has the nonlocal keyword for that (just declare nonlocal count in countiter to match your desired behaviour, in python 2.7, you have to emulate this via mutable objects (since inner function can read and mutate outer functions variables, just not assign to them).
so you can in fact do:
def do():
count = [0,]
def countiter(iter):
for i in iter:
count[0] += 1
yield i
list(countiter(randiter(0.99)))
return count[0]
Related
I have to execute the following code wherein I will be calling the function main again and again.
so here as I need to use i = i+1, I need to declare and initialize i in the first place right, but when i call the main function it again defines i=0 and the whole purpose of i = i+1 is lost.
How can I solve this error?
I have given the condition just as an example.
Basically what I want is i should be initialized only once, inspite of how many number of times main is called.
def main():
i = 0
if 0<1:
i = i+1
y = i
There are a couple ways to do this that don't involve globals. One is capture the value of i in a closure and return a new function that increments this. You will need to call the initial function once to get the returned function:
def main():
i = 0
def inner():
nonlocal i
i += 1
return i
return inner
f = main()
f()
# 1
f()
# 2
You can also create a generator which is a more pythonic way to do this. The generator can be iterated over (although use caution since it iterates forever) or you can get a single value by passing it to next():
def main():
i = 1
while True:
yield i
i += 1
f = main()
next(f)
# 1
next(f)
# 2
You can also use itertools.count
So you haven't declared i as a global variable
Do something like this
global i
i = 0
def main():
if 0<1:
global i
i = i+1
y = i
The reason behind this is because inside a function all the variables are local meaning they only exist inside the function while the function is called, so if you want a function to be able to change a variable for the whole code, you'll need to announce it as a global so python knows to change the value of it for the entire code
I'm not sure exactly what you are trying to do, but I believe there is an easier way to do whatever it is you are doing
It looks like you want to maintain state in a function call which is a good reason to convert it to a class.
class MyClass:
def __init__(self):
self.i = 0
def main(self):
self.i += 1
y = self.i
myclass = MyClass()
myclass.main()
myclass.main()
print(myclass.i)
I'd like to take an example code for this:
def coun(n):
count = 0
def counter():
nonlocal count
if count < n:
count += 1
return count
return counter
cntrl = coun(4)
print(cntrl())
why must we assign the function to an identifier, further more in the print statement, the cntrl is invoked using parenthesis, and in the return statement of the function coun the counter is not returned using parenthesis. What is this?(I'm just a novice at python)
Assigning functions to identifiers isn't neccesary to invoke them.
Consider simple example:
def function_factory():
def f(x):
return x
return f
You may assign function returned from factory to identifier and use it as any other named function:
my_f = function_factory()
assert my_f(1) == 1
Or you can drop intermediate assignment and do it in one line:
assert function_factory()(1) == 1
It's not
Because you are doing return counter rather than return counter() you are returning a function rather than the result of that function, in order to get the result you need to call this function. You can do this, as you have done, by assigning it to a variable or you can call it immediately with the usual function call convention:
print(coun(4)())
I need one global variable s = set() to help me with certain recursive function. After I ran the function, I want it to be an empty set again. Is there any simple way for me to do it? I'm using python 3.4.1
ADD: So I want to traverse a tree to get the number of distinct nodes. In order to do that I use a global variable SET = set() to keep records of the same nodes. After I called the function, I want to reset the global variable SET.
SET = set()
def distinct_node_count(root):
global SET
if not root.children:
if root.value.__repr__() not in SET:
SET.add(root.value.__repr__())
return 1
else:
return 0
else:
if root.value.__repr__() not in SET:
SET.add(root.value.__repr__())
return 1 + sum([distinct_node_count(child) for child in root.children])
else:
return sum([distinct_node_count(child) for child in root.children])
don't use a global variable but a paramater with a default value
something like this
def recursive(oneparam, secondparam,*, s=None):
if s is None:
s = set()
if secondparam < 0:
return 0
return 1 + recursive(oneparam,secondparam-1,s=s)
The previous version don't change really the contract but if you absolutly don't want to be able to add an additional parameter just use an auxiliary function
def recursive(oneparam, secondparam):
def inner(oneparam, secondparam, s):
if secondparam < 0:
return 0
return 1 + inner(oneparam,secondparam-1,s)
inner(oneparam,secondparam,set())
OK, i'm using Python 2.7.3 and here is my code:
def lenRecur(s):
count = 0
def isChar(c):
c = c.lower()
ans=''
for s in c:
if s in 'abcdefghijklmnopqrstuvwxyz':
ans += s
return ans
def leng(s):
global count
if len(s)==0:
return count
else:
count += 1
return leng(s[1:])
return leng(isChar(s))
I'm trying to modify the variable count inside the leng function. Here are the things that I've tried:
If I put the variable count outside the lenRecur function it works fine the first time, but if I try again without restarting python shell, the count (obviously) doesn't restart, so it keeps adding.
If I change the count += 1 line for count = 1 it also works, but the output is (obviously) one.
So, my goal here is to get the length of the string using recursion, but I don't know how to keep track of the number of letters. I've searched for information about global variables, but I am still stuck. I don't know if i haven't understood it yet, or if I have a problem in my code.
Thanks in advance!
count in lenRecur is not a global. It is a scoped variable.
You'll need to use Python 3 before you can make that work in this way; you are looking for the nonlocal statement added to Python 3.
In Python 2, you can work around this limitation by using a mutable (such as a list) for count instead:
def lenRecur(s):
count = [0]
# ...
def leng(s):
if len(s)==0:
return count[0]
else:
count[0] += 1
return lenIter(s[1:])
Now you are no longer altering the count name itself; it remains unchanged, it keeps referring to the same list. All you are doing is altering the first element contained in the count list.
An alternative 'spelling' would be to make count a function attribute:
def lenRecur(s):
# ...
def leng(s):
if len(s)==0:
return leng.count
else:
leng.count += 1
return lenIter(s[1:])
leng.count = 0
Now count is no longer local to lenRecur(); it has become an attribute on the unchanging lenRecur() function instead.
For your specific problem, you are actually overthinking things. Just have the recursion do the summing:
def lenRecur(s):
def characters_only(s):
return ''.join([c for c in s if c.isalpha()])
def len_recursive(s):
if not s:
return 0
return 1 + len_recursive(s[1:])
return len_recursive(characters_only(s))
Demo:
>>> def lenRecur(s):
... def characters_only(s):
... return ''.join([c for c in s if c.isalpha()])
... def len_recursive(s):
... if not s:
... return 0
... return 1 + len_recursive(s[1:])
... return len_recursive(characters_only(s))
...
>>> lenRecur('The Quick Brown Fox')
16
I think You can pass count as second argument
def anything(s):
def leng(s, count):
if not s:
return count
return leng(s[1:], count + 1)
return leng(isChar(s), 0)
this should work better than muting objects from outer scope such as using mutable objects (list or dict) or monkey-patching function itself for example.
You need to make the variable count a function variable like
def lenRecur(s):
lenRecur.count = 0
However, I see a few problems with the code.
1) If you are trying to find the number of alphabets in a string through recursion, this one will do:
def lenRecur(s):
def leng(s, count = 0):
if not s:
return count
else:
count += int(s[0].isalpha())
return leng(s[1:], count)
return leng(s)
But still I would prefer having a single function to do the task, like there will be no leng method at all.
2) If your goal is just to find the number of alphabets in a string, I would prefer list comprehension
def alphalen(s):
return sum([1 for ch in s if ch.isalpha()])
If this is anything other than learning purpose, I suggest you to avoid recursion. Because, the solution cannot be used for larger strings(lets say, finding the alphabet count from contents of a file). You might hit the RunTimeError of Maximum Recursion Depth Exceeded.
Even though you can work around this through setting the recursion depth through setrecursionlimit function, I suggest you to go for other easy ways. More info on setting the recursionlimit here.
Define it outside all function definitions, if you want to use it as a global variable:
count = 0
def lenRecur(s):
or define it as a function attribute:
def lenRecur(s):
lenRecur.count = 0
def isChar(c):
This has been fixed in py3.x where you can use the nonlocal statement:
def leng(s):
nonlocal count
if len(s)==0:
You don't need count. The below function should work.
def leng(s):
if not s:
return 0
return 1 + leng(s[1:])
Global variable in recursion is very tricky as the depth reaches to its last state and starts to return back to the first recursive call the values of local variables change so we use global variables. the issue with global variables is that when u run the func multiple times the global variable doesn't reset.
I am trying to create a script that sets a local variable, references it from a function, and can return the manipulated value back to the main scope (or whatever it's called; I'm new to Python)
I have simplified my code to show the utmost basics of what I am trying to accomplish, which is to import a local from the module into a function block, I think.
I have gotten this to work by using globals, but that isn't the best solution . . .
chambersinreactor = 0;
cardsdiscarded = 0;
def find_chamber_discard():
"""Find chambers and discard in row (reads each player slot)"""
chambersinreactor = 0; # Resets the variable, not what I want
cardsdiscarded = 0; # Resets the variable, not what I want
chambersinreactor += 1
cardsdiscarded += 1
return # Don't know what to put here
find_chamber_discard()
print chambersinreactor # prints as 0, should be 1
print cardsdiscarded # prints as 0, should be 1
Functions shouldn't have to know what scope they're called from; the point of a function is to make a re-usable block of code that can be invoked multiple times from different places.
You communicate information to a function by passing it through its input variables. The function communicates information back to its caller by returning it.
Managing the variables of a scope is the job of the code in that scope not any functions it invokes. If you need to set variables to values determined by a function, then you have the function return those values and you use them to set the variables. If the values the function is calculating depend on the values of variables you have in the calling scope, then you need to pass them to the function as arguments. The function you're calling shouldn't have to know what variables you're using, and shouldn't be able to mess with them.
Putting that all together, what you want to do is something like this:
def find_chamber_discard(chambersinreactor, cardsdiscarded):
chambersinreactor += 1
cardsdiscarded += 1
return (chambersinreactor, cardsdiscarded)
chambersinreactor = 0;
cardsdiscarded = 0;
chambersinreactor, cardsdiscarded = find_chamber_discard(chambersinreactor, cardsdiscarded)
print chambersinreactor
print cardsdiscarded
There are ways to get around this with global variables or manipulating mutable data structures, but ultimately they make your program less flexible and more likely to contain errors that will be difficult to spot. There is a place for those techniques, but the first method you reach for to communicate information to and from functions really should be passing arguments and receiving return values.
One approach is to use mutable values, like dicts or lists:
settings = dict(
chambersinreactor = 0,
cardsdiscarded = 0
)
def find_chamber_discard():
settings['chambersinreactor'] += 1
settings['cardsdiscarded'] += 1
find_chamber_discard()
print settings['chambersinreactor']
print settings['cardsdiscarded']
However, if you have a function that is changing some state, you're probably better off wrapping that all up in class, as that's what they're for:
class CardCounter(object):
def __init__(self):
chambersinreactor = 0
cardsdiscarded = 0
def find_chamber_discard(self, hand):
for card in hand:
if card.is_chamber:
self.chambersinreactor += 1
if card.is_discarded:
self.cardsdiscarded += 1
If what you're doing is counting, maybe you could use Counter:
from collections import Counter
def test_for_chamberness(x): return x == 'C'
def test_for_discarded(x): return x == 'D'
def chamber_or_discard(card):
if test_for_chamberness(card):
return 'chambersinreactor'
if test_for_discarded(card):
return 'cardsdiscarded'
hand = ['C','C','D','X','D','E','C']
print Counter(
x for x in (chamber_or_discard(card) for card in hand) if x is not None
)
Personally, I'd go for the class approach, perhaps even wrapping Counter, as it keeps all the associated functionality together.
#!/usr/bin/env python
chambersinreactor = 0; cardsdiscarded = 0;
def find_chamber_discard():
chambersinreactor = 0
cardsdiscarded = 0
chambersinreactor += 1
cardsdiscarded += 1
return(chambersinreactor, cardsdiscarded)
#Here the globals remain unchanged by the locals.
#In python, a scope is similar to a 'namespace'
find_chamber_discard()
print chambersinreactor #prints as 0
print cardsdiscarded
#I've modified the function to return a pair (tuple) of numbers.
#Above I ignored them. Now I'm going to assign the variables in the
#main name space to the result of the function call.
print("=====with assignment===")
(chambersinreactor, cardsdiscarded) = find_chamber_discard()
print chambersinreactor # now prints as 1
print cardsdiscarded
# Here is another way that doesn't depend on returning values.
#Pass a dictionary of all the main variables into your function
#and directly access them from within the function as needed
print("=======using locals===")
def find_chamber_discard2(_locals):
_locals['chambersinreactor'] += 1
_locals['cardsdiscarded'] += 1
return
find_chamber_discard2(locals())
print chambersinreactor #incremented the value, which was already 1
print cardsdiscarded