I am trying to understand local/global/nonlocal capture rules for python scoping and have encountered some asymmetric behavior, here is an example:
def test():
i = 0
d = dict()
def next():
d[len(d)] = 'foo' # why is nonlocal d not required?
nonlocal i # Required to pull 'i' into next.locals()
i += 1
while i < 10:
next()
test()
From the above snippet we have variables d and i declared and defined as dict and int types respectively. However in the nested function next only d can be reached, i requires the nonlocal term to pull i into the function's scope.
I next theorized that non-referenceable types in python get lifted into the context of it's children's scope.
However this next example contradicts my theory:
def test2():
def If():
return True if qn == None else qn
def Ask():
nonlocal qn
qn = i < lim
return If()
qn = None
i = 0
lim = 5
while i < 10:
i += 1
print(i, Ask())
Notice that in test2's Ask function I do not need to declare nonlocal i and nonlocal lim but require nonlocal qn.
Is this behavior expected? I would assume either both should require nonlocal or neither would require it.
Is there a language specification I can reference for similar types of behavior?
Related
this code works well when I try to change dictionary in closure
def a():
x = {'a':'b'}
def b():
x['a'] = 'd'
print(x)
return b
>>> b = a()
>>> b()
{'a':'d'}
output is meeting my expectation. but why the code below doesn't work?
def m():
x = 1
def n():
x += 1
print(x)
return n
>>> n = m()
>>> n()
UnboundLocalError: local variable 'x' referenced before assignment
Honestly, I've known that we can use nonlocal x statement to solve this problem
But can anybody explain the reason more deeply for me? what the difference between a dictionary and a number
Thanks!
Python has a great FAQ specifically on this.
In short, when you modify a dictionary, or any mutable object, you modify the same object, so you don't re-assign the variable. In case of an integer, since it's immutable, by doing a += you create a new object and put it into x. Since x is now defined inside the inner function, but you're trying to bring data from the outer function, you have an issue.
You can check if it's the same object using id().
I know that return is like throwing out a value at the end of an operation and that it actually stops the iteration or the function in which it's residing. I am having this very simple piece of code where classmethods & class variables are used.
class Person:
number_of_people = 0
def __init__(self, name):
#Person.number_of_people +=1
Person.add_person()
#classmethod
def get_person_count(cls):
return cls.number_of_people
#classmethod
def add_person(cls):
# return cls.number_of_people+1 <-- this does not work. Output is 0 and 0. Why?
cls.number_of_people += 1 #<-- this works
P1 = Person("Rups")
print(P1.get_person_count())
P2 = Person("RG")
print(P2.get_person_count())
As I have commented on the lines, why is my method giving output 0 both times and not the expected output(1 & 2), which is achieved using plan variable modification? Either way, I thought I should be able to use the value given out by add_person method in the init method, since there is no looping involved.
Returning a value does not mean it is modifying a variable. It just means that something can use what is returned. The difference is that cls.number_of_people += 1 changes number_of_people to it's value + 1 (due to the = sign), while return cls.number_of_people+1 takes number_of_people + 1 and "throws" it for something else to use.
What this means is that if add_person returns a value, anytime you call add_person(), there is a value that can be used.
# {...}
def add_person(cls):
return cls.number_of_people + 1
P1 = Person("Rups")
print(P1.add_person()) # prints 1 (number_of_people which is 0, then add 1)
print(P1.add_person()) # still prints 1
I have part of a function I would like to turn into another function. I want this new function to be able to edit the variables in in the parent function. Is this possible in python.
I know in other languages that a class can inherent their parents variables and function. I am wondering if there is something similar to this in python?
check here for scoping then here and here for closures. You are ideally looking for enclosing functions. The variables defined within the enclosing functions are available to the sub-functions as though they were globally defined. Most of these are widely dealt with in other languages.
def m(x,y):
z = 2
j = 4
def n():
return x+y+z+j
return n()
m(3,1)
10
is that what you are looking for !
class Parent:
# two class variables x,y
x = 100
y = 100
def __init__(self):
pass
def sum_from_parent(self):
return self.x+self.y
class Child(Parent):
def __init__(self):
super().__init__() # init super class to create x,y variables
def sum_child(self):
# edit base class variables
x_in_child = Parent.x+20
y_in_child = Parent.y+20
return(x_in_child+y_in_child)
c = Child()
print("sum in parent = ", c.sum_from_parent())
print("sum in child = ", c.sum_child())
answer will be
sum in parent = 200
sum in child = 240
I want to have a global variable changed form inside a function. The global variable is an integer. I am getting an error when trying to do so. This is a simplified version of what I am trying to do:
variable = 3
def test():
b = 5
if b > 0:
variable -= 1
print(variable)
else:
print('fail')
test()
Can anyone help me in finding a way to reduce the integer variable by 1 every time the function test runs?
When referring to a variable that's outside of a function that you don't pass in as a parameter, you must declare it as global before referencing it. Add global variable to the beginning of your function and it should work.
variable = 3
def test():
b = 5
global variable
variable -= 1
if b > 0:
print(variable)
else:
print('fail')
test()
test()
test()
test()
test()
test()
output:
2
1
0
-1
-2
-3
Note that the condition will not satisfy to fail because we are not doing anything with b that is equals to 5 forever.
I have two functions. They are not a part of any class. Just individual functions.
function f1 calls f2. What I would like to do is print in f2 the variables declared in f1.
How can I achieve this?
def f1():
a = 10
b = 20
f2()
def f2():
print(a)
print(b)
def f1():
a = 10
b = 20
f2(locals())
def f2(dic):
for key in dic:
print(key, '=', dic[key])
f1()
locals() returns the the local variables and values in a dictionary.
Calling f2 inside f1 captures the locals of f1 and is passed as
the argument dic for processing in f2.
You could define the variables outside of the function first and then use the global modifier as in the second example. In this simple case however it would probably make more sense to just pass the variables to f2() (example 1).
You could also take a look at Access a function variable outside the function without using `global` if this is what you are looking for?
You generally also don't want to have code that checks what the caller function is as in this example. In any case your code must not be able to reach a state where a and b do not (yet) exist.
example 1
def f1():
a = 10
b = 20
f2(a, b)
def f2(a, b):
print(a)
print(b)
As stated in the comments this is not what you were looking for, so that's why you also have this possibility:
example 2
a=5
b=5
def f1():
global a
global b
a = 10
b = 20
f2()
def f2():
print(a)
print(b)
Calling f1() will print 10 and 20.