Does Python not support closures unlike Lua? [duplicate] - python

This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 7 months ago.
I was learning about closures in Lua and came accross this code that works in Lua:
function newcounter()
local i = 0
function dummy()
i = i + 1
return i
return dummy
x = newcounter()
print(x())
-- this outputs 1, i.e., dummy uses the i variable from its enclosing function newcounter
I thought Python also supports a similar closure. So I tried the following code in Python3:
def nc():
i = 0
def dummy():
i = i + 1
return i
return dummy
x = nc()
print(x())
However, when I run the above Python code, I get the error that i is accessed before being assigned!
Traceback (most recent call last):
File "/tmp/test.py", line 9, in <module>
print(x())
File "/tmp/test.py", line 4, in dummy
i = i + 1
UnboundLocalError: local variable 'i' referenced before assignment
Does this mean Python does not support closures? Or am I misunderstanding something about closures?

Python decides the scope of variables based on where it finds assignments to them. Because you have an assignment to i in the form i = ..., i will be a local variable scoped to dummy by default, but you can override that with a nonlocal statement:
def nc():
i = 0
def dummy():
nonlocal i
i = i + 1
return i
return dummy
x = nc()
print(x())
So yes, Python has closures.

Assigning to a name within a Python function makes it local by default, from the beginning of the function to the end. If you want to assign to names while having them remain tied to the closure scope, you must explicitly declare said name nonlocal:
def nc():
i = 0
def dummy():
nonlocal i # Makes code work as expected by forcing loads and stores to apply to
# closed-upon i
i = i + 1
return i
return dummy

Python supports closures. The issue you're dealing with here has to do with how scoping works, which is explained here: UnboundLocalError on local variable when reassigned after first use. Note that you can get the same error by referencing a global variable.
Here's an example closure:
def nc(i):
def dummy():
return i
return dummy
x = nc(9)
i = 8
print(x()) # -> 9

Related

Python Function Not Changing Variable [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Closed 2 years ago.
I am a c++ programmer and am learning pygame so I am very new to python. I noticed this behavior of functions and don't know what to do about it:
let's say we have a global variable:
x = 10
Now let's say we have a function that changes the value of x:
def foo():
x = 100
Now, inside my main pygame loop, if I call foo(), the variable x is still 10 after the function call. How is this happening???
Inside the function local scope value of x is changed. The x defined outside the function has global scope. To change global value try global var_name statement inside function before updating value
def foo():
global x
x = 100
Inside your function, you implicitly create another variable x, and then set it to 100. To change the global variable try this:
def foo():
global x
x = 100

Python global keyword [duplicate]

This question already has answers here:
Is it possible to modify a variable in python that is in an outer (enclosing), but not global, scope?
(9 answers)
Closed 5 months ago.
I am confused with the global keyword behavior in below code snippet, I was expecting 30, 30, 30 in all 3 prints.
def outer_function():
#global a ###commented intentionally
a = 20
def inner_function():
global a
a = 30
print('a =',a)
inner_function()
print('a =',a)
a = 10
outer_function()
print('a =',a)
#Output:
#30
#20 #Expecting 30 here
#30
All the confusion coming from "global a" after outer function definition. As my understanding at this point of time is " All the reference and assignment to variable become globally reflected on declaration of global keyword on that variable". If I am uncommenting that first global statement I am getting expected output 30,30,30.
Why global declaration inside inner_function and value change does not reflect on 2nd print i:e to outer_function(or outer scope), whereas got reflected in global namespace.
A common acronym to be familiar with is LEGB:
Local
Enclosed
Global
Built-in
This is the order in which Python will search the namespaces to find variable assignments.
Local
The local namespace is everything that happens within the current code block. Function definitions contain local variables that are the first thing that is found when Python looks for a variable reference. Here, Python will look in the local scope of foo first, find x with the assignment of 2 and print that. All of this happens despite x also being defined in the global namespace.
x = 1
def foo():
x = 2
print(x)
foo()
# prints:
2
When Python compiles a function, it decides whether each of the variables within the definition code block are local or global variables. Why is this important? Let's take a look at the same definition of foo, but flip the two lines inside of it. The result can be surprising
x = 1
def foo():
print(x)
x = 2
foo()
# raises:
UnboundLocalError: local variable 'x' referenced before assignment
This error occurs because Python compiles x as a local variable within foo due to the assignment of x = 2.
What you need to remember is that local variables can only access what is inside of their own scope.
Enclosed
When defining a multi-layered function, variables that are not compiled as local will search for their values in the next highest namespace. Here is a simple example.
x = 0
def outer_0():
x = 1
def outer_1():
def inner():
print(x)
inner()
outer_1()
outer_0()
# print:
1
When inner() is compiled, Python sets x as a global variable, meaning it will try to access other assignments of x outside of the local scope. The order in which Python searches for a value of x in moving upward through the enclosing namespaces. x is not contained in the namespace of outer_1, so it checks outer_0, finds a values and uses that assignment for the x within inner.
x --> inner --> outer_1 --> outer_0 [ --> global, not reached in this example]
You can force a variable to not be local using the keywords nonlocal and global (note: nonlocal is only available in Python 3). These are directives to the compiler about the variable scope.
nonlocal
Using the nonlocal keyword tells python to assign the variable to first instance found as it moves upward through the namespaces. Any changes made to the variable will be made in the variable's original namespace as well. In the example below, when 2 is assigned x, it is setting the value of x in the scope of outer_0 as well.
x = 0
def outer_0():
x = 1
def outer_1():
def inner():
nonlocal x
print('inner :', x)
x = 2
inner()
outer_1()
print('outer_0:', x)
outer_0()
# prints:
inner : 1
outer_0: 2
Global
The global namespace is the highest level namespace that you program is running in. It is also the highest enclosing namespace for all function definitions. In general it is not good practice to pass values in and out of variables in the global namespace as unexpected side effects can occur.
global
Using the global keyword is similar to non-local, but instead of moving upward through the namespace layers, it only searches in the global namespace for the variable reference. Using the same example from above, but in this case declaring global x tells Python to use the assignment of x in the global namespace. Here the global namespace has x = 0:
x = 0
def outer_0():
x = 1
def outer_1():
def inner():
global x
print('inner :', x)
inner()
outer_1()
outer_0()
# prints:
0
Similarly, if a variable is not yet defined in the global namespace, it will raise an error.
def foo():
z = 1
def bar():
global z
print(z)
bar()
foo()
# raises:
NameError: name 'z' is not defined
Built-in
Last of all, Python will check for built-in keywords. Native Python functions such as list and int are the final reference Python checks for AFTER checking for variables. You can overload native Python functions (but please don't do this, it is a bad idea).
Here is an example of something you SHOULD NOT DO. In dumb we overload the the native Python list function by assigning it to 0 in the scope of dumb. In the even_dumber, when we try to split the string into a list of letters using list, Python will find the reference to list in the enclosing namespace of dumb and try to use that, raising an error.
def dumb():
list = 0
def even_dumber():
x = list('abc')
print(x)
even_dumber()
dumb()
# raises:
TypeError: 'int' object is not callable
You can get back the original behavior by referencing the global definition of list using:
def dumb():
list = [1]
def even_dumber():
global list
x = list('abc')
print(x)
even_dumber()
dumb()
# returns:
['a', 'b', 'c']
But again, DO NOT DO THIS, it is bad coding practice.
I hope this helps bring to light some of how the namespaces work in Python. If you want more information, chapter 7 of Fluent Python by Luciano Ramalho has a wonderful in-depth walkthrough of namespaces and closures in Python.
From the documentation:
The global statement is a declaration which holds for the entire
current code block. It means that the listed identifiers are to be
interpreted as globals.
Note it only applies to current code block. So the global in inner_function only applies within inner_function. Outside of it, the identifier is not global.
Note how “identifier” is not the same as “variable”. So what it tells the interpreter is “when I use identifier a within this code block, do not apply normal scope resolution, I actually mean the module-level variable, ”.
Just uncomment your global command in the outer_function, otherwise you're declaring a local variable with value 20, changing a global variable then printing that same local variable.
It's not a good idea use global variabilities. If you want only reset the value of a variable, you just use this lines:
def outer_function():
a = 20
def inner_function():
a = 30
print('a =',a)
return a
a = inner_function()
print('a =',a)
return a
a = 10
a = outer_function()
print('a =',a)

Python name shadowing confusion [duplicate]

This question already has answers here:
What is the problem with shadowing names defined in outer scopes?
(10 answers)
Closed 8 years ago.
So I've got some code similar to this (this code reproduces my question, even if it doesn't do anything useful):
def fn():
l = ["foo", "bar", "baz"]
print map( lambda f : len(f), l )
for i, f in enumerate(l):
print i, f
And PyCharm is reporting that my declaration of lambda f "Shadows name f from outer scope". This appears to be because of the variable being reused in the call to enumerate() in the following line.
The code works as expected, but what's happening here? Am I correct in thinking that Python is deciding that f is a local variable in fn and warning me that the use of f inside the lambda isn't going to be the same f defined locally - even though the lambda makes use of the variable name f first?
Other than renaming variables, is there a best practice for avoiding this - or should I just use my judgement and ignore the warning in this instance?
Assigning to a variable anywhere in the definition of a function makes it local to the function. A more typical example is
x = 3
def foo():
print x
x = 2
foo()
When foo is defined, the presence of x = 2 without a previous global x statement makes x a local variable. When foo is called, the local variable x is not yet defined when print x is called, resulting in an UnboundLocalError. It doesn't matter that there is a global variable by the same name.
In your example, the for loop is a kind of implicit assignment to the variable f, so f is local to fn. The warning is to let you know that the lambda argument f takes precedence over the value of f in fn when it comes time to evaluate len(f).

Using not defined variable in function body [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
There is this code:
def f():
x = m
m = 2
def g():
x = m
f() # UnboundLocalError: local variable 'm' referenced before assignment
g() # NameError: global name 'm' is not defined
In both function bodies there is used variable m which is not defined when used but the error messages are different. Do Python know what variables are defined in function before using them (like in function f)? Why the error messages are different?
If there is an assignment to a variable anywhere in a function, then it is considered a local variable everywhere in that function. This means that for the function f(), even though the assignment to m happens after the attempt to access m, the line x = m will only look for the name m within the local scope. This is why the error message for f() refers to m as a local variable.
In the function g() there is no assigment to m, so the line x = m will look for m using the order described here:
the innermost scope, which is searched first, contains the local
names
the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
the next-to-last scope contains the current module’s global names
the outermost scope (searched last) is the namespace containing built-in names
The error message for g(), "global name 'm' is not defined", refers to the global scope because that is the last location that was searched (except built-in, but it would be confusing to have a message like "the name 'm' was not found in the built-in namespace").
Note that you can use the global or nonlocal statements to change this behavior (nonlocal only exists in Python 3.x).
Python checks it as soon as you call it.
When importing, and typing directly into the interpreter, it only cares if you broke any syntax rules. it doesnt care about locals or globals at this level.
>>> def foo():
... print locals()
... bar = 34
... print locals()
... DIP = SET
...
>>>
>>> foo()
{}
{'bar': 34}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in foo
NameError: global name 'SET' is not defined
it runs from top to bottom, and checks locals() and globals() if it sees that variable then its okay and does whatever with it.
it even works with definitions and sub definitions.. or anything else you are assigning
>>> def foo():
... bar()
... def bar():
... print("never gonna give you up")
...
>>>
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'bar' referenced before assignment
Yes. If you assign to a variable at any point in a function (without using the global keyword), Python treats all references to that name in the function as local.
When you execute a function, you actually invoke __call()__ on a function object.
The function object is created in the scripts global namespace when the script is parsed.
Created, but not executed.
As part of the parsing process, the objects namespace is computed. So the interpreter can actually know which variable exists and when.
def f():
x = m
m = 2
When the above function parsed python thinks that m is local variable as it finds m = 2, so when the function is actually called x = m will raise error as m is not defined yet in local scope.
def g():
x = m
In this python thinks that m is going to be some value from the global scope, it searches the global namespace first and then built-ins, but when m is not found anywhere the error is raised.
>>> m = 1
>>> def g():
x = m
>>> g() #works fine because `m` is found in global scope
>>> def g():
x = sum
>>> g() # sum is found in built-ins
To modify a global variable use global:
>>> m = 1
>>> def g():
global m
m += 1
...
>>> g()
>>> m
2
You need to use global m inside the function

Why nested functions can access variables from outer functions, but are not allowed to modify them [duplicate]

This question already has answers here:
Is it possible to modify a variable in python that is in an outer (enclosing), but not global, scope?
(9 answers)
Closed 8 years ago.
In the 2nd case below, Python tries to look for a local variable. When it doesn't find one, why can't it look in the outer scope like it does for the 1st case?
This looks for x in the local scope, then outer scope:
def f1():
x = 5
def f2():
print x
This gives local variable 'x' referenced before assignment error:
def f1():
x = 5
def f2():
x+=1
I am not allowed to modify the signature of function f2() so I can not pass and return values of x. However, I do need a way to modify x. Is there a way to explicitly tell Python to look for a variable name in the outer scope (something similar to the global keyword)?
Python version: 2.7
In Python 3.x this is possible:
def f1():
x = 5
def f2():
nonlocal x
x+=1
return f2
The problem and a solution to it, for Python 2.x as well, are given in this post. Additionally, please read PEP 3104 for more information on this subject.
def f1():
x = { 'value': 5 }
def f2():
x['value'] += 1
Workaround is to use a mutable object and update members of that object. Name binding is tricky in Python, sometimes.

Categories