modify locals() like globals(), to insert variables into scope - python

(My python version is 3.7.0 on Ubuntu 19.10)
locals() and globals() produce dict-like objects that contain the references that are currently in scope. When a new key is added to globals(), it becomes available in global scope:
# the first two lines can be deleted
# they are just to make sure that I don't accidentally
# have a definition of a left in global scope
a = 1
del a
globals().update({'a':1})
print(a) # prints 1
This also works from inside a function definition. Please note, at the time when the function was defined, there was no global variable a. It is only created when the function is executed:
del a
def fun():
globals().update({'a':1})
print(a)
fun() # prints 1
This does not work with locals():
def fun():
locals().update({'a':1})
print(a)
fun() # NameError: name 'a' is not defined
Curiously, if I define a and then delete it, the error changes:
def fun():
a = 1
del a
locals().update({'a':1})
print(a) # UnboundLocalError: local variable 'a' referenced before assignment
fun()
And, although it is possible to update globals() and then to access the new reference inside a function, this is no longer possible, once a reference of the same name has at some point been in local scope:
def fun():
a = 1
assert 'a' in locals()
del a
assert 'a' not in locals()
globals().update({'a':1})
print(a) # UnboundLocalError
fun()
And another test, regarding the behaviour of locals() in global scope, out of a function:
a = 1
del a
locals().update({'a':1})
print(a) # prints 1
What are the semantics here? Why do the error messages change between NameError and UnboundLocalError? Is it possible to insert a reference into local scope?

Related

How can a function access variables that are not defined inside the function?

I recently started studying Python and I came across an example that I did not understand:
def teste():
print(a, b)
a = 5
b = 4
teste() # Outputs '5 4'
What is happening here? Is teste() able to access a and b because those variables are globals?
Short answer, yes. a and b are global variables in that sense.
Long answer, as long as you keep the variable names on the right side of an assignment or just pass them to a function within a function, they'll act as global variables.
What's happening is that Python will first look in the local scope of that function for the variable names and only if it doesn't find them go for the next scope, which is the global scope in your example.
Function foo has no variable named a so Python searches in the next available scope
a = "global a"
def foo():
# No variable 'a' in local scope of foo()
# Getting value of 'a' from the scope where foo() is called
print(a)
foo() # Prints "global a"
If you want to declare a variable as global inside your function, you can use the global keyword. With that you can set a new value to your now global variable:
a = "global a"
def foo():
global a
a = "Changed in function"
print(a) # Prints "global a"
foo() # assigns new value to a
print(a) # Prints "Changed in function"
If you don't use the global keyword, as soon as you use the same variable name inside a function on the left side of an assignment, you are creating a local variable overshadowing the global variable with the same name:
a = "global a"
def foo():
a = "local a"
print(a)
print(a) # Prints "global a"
foo() # Prints "local a"
print(a) # Prints "global a"

Why do I have do "global" a variable that's already global? [duplicate]

What is a global statement? And how is it used? I have read Python's official definition;
however, it doesn't make a lot of sense to me.
Every "variable" in python is limited to a certain scope. The scope of a python "file" is the module-scope. Consider the following:
#file test.py
myvariable = 5 # myvariable has module-level scope
def func():
x = 3 # x has "local" or function level scope.
Objects with local scope die as soon as the function exits and can never be retrieved (unless you return them), but within a function, you can access variables in the module level scope (or any containing scope):
myvariable = 5
def func():
print(myvariable) # prints 5
def func2():
x = 3
def func3():
print(x) # will print 3 because it picks it up from `func2`'s scope
func3()
However, you can't use assignment on that reference and expect that it will be propagated to an outer scope:
myvariable = 5
def func():
myvariable = 6 # creates a new "local" variable.
# Doesn't affect the global version
print(myvariable) # prints 6
func()
print(myvariable) # prints 5
Now, we're finally to global. The global keyword is the way that you tell python that a particular variable in your function is defined at the global (module-level) scope.
myvariable = 5
def func():
global myvariable
myvariable = 6 # changes `myvariable` at the global scope
print(myvariable) # prints 6
func()
print(myvariable) # prints 6 now because we were able
# to modify the reference in the function
In other words, you can change the value of myvariable in the module-scope from within func if you use the global keyword.
As an aside, scopes can be nested arbitrarily deeply:
def func1():
x = 3
def func2():
print("x=",x,"func2")
y = 4
def func3():
nonlocal x # try it with nonlocal commented out as well. See the difference.
print("x=",x,"func3")
print("y=",y,"func3")
z = 5
print("z=",z,"func3")
x = 10
func3()
func2()
print("x=",x,"func1")
func1()
Now in this case, none of the variables are declared at the global scope, and in python2, there is no (easy/clean) way to change the value of x in the scope of func1 from within func3. That's why the nonlocal keyword was introduced in python3.x . nonlocal is an extension of global that allows you to modify a variable that you picked up from another scope in whatever scope it was pulled from.
mgilson did a good job but I'd like to add some more.
list1 = [1]
list2 = [1]
def main():
list1.append(3)
#list1 = [9]
list2 = [222]
print list1, list2
print "before main():", list1, list2
>>> [1] [1]
main()
>>> [1,3] [222]
print list1, list2
>>> [1, 3] [1]
Inside a function, Python assumes every variable as local variable
unless you declare it as global, or you are accessing a global variable.
list1.append(2)
was possible because you are accessing the 'list1' and lists are mutable.
list2 = [222]
was possible because you are initializing a local variable.
However if you uncomment #list1 = [9], you will get
UnboundLocalError: local variable 'list1' referenced before assignment
It means you are trying to initialize a new local variable 'list1' but it was already referenced before,
and you are out of the scope to reassign it.
To enter the scope, declare 'list1' as global.
I strongly recommend you to read this even though there is a typo in the end.
a = 1
def f():
a = 2 # doesn't affect global a, this new definition hides it in local scope
a = 1
def f():
global a
a = 2 # affects global a
Basically it tells the interpreter that the variable its given should be modified or assigned at the global level, rather than the default local level.
You can use a global variable in other functions by declaring it as global in each function that modifies it
Python wants to make sure that you really know that's what you're playing with by explicitly requiring the global keyword.
See this answer

Unbound local variables in a class definition are looked up in the global namespace - what does it mean?

The last paragraph of https://docs.python.org/3/reference/executionmodel.html#resolution-of-names says
Class definition blocks and arguments to exec() and eval() are special in the context of name resolution. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace.
What does the last sentence of the quoted text mean? At first I inferred from it that the following code will print 1
a = 1
def foo():
a = 2
def bar():
class Bar:
b = a
print(Bar.b)
bar()
foo()
but I was wrong - a module consisting of the code above, when run, prints 2, i.e. the name a in the class definition, even though it's not bound in the class definition block and not bound in the local block just outside of it, isn't looked up in the global namespace, contrary to what the docs say.
I tried another code snippet described below (using a del statement, which is a construct that binds the variable in it)
a = 1
def foo():
a = 2
def bar():
class Bar:
del a
print(Bar.b)
bar()
foo()
but the del statement raises NameError: name 'a' is not defined.
So, I don't understand, what does that sentence mean?
According to the docs,
if a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global.
In your first code block, a is not bound to anything in your class Bar definition, so it is not a local variable of that block.
One way of binding a name is by using it on the left-hand side of an assignment statement. Here's an example.
a = 1
def foo():
a = 2
class Bar:
b = a
a = 3
print(Bar.b)
foo()
Result:
1
This demonstrates the principle of "unbound local variables are looked up in the global namespace" -- b = a uses the value of the global a rather than the value of the a local to foo.
In your second example, a is considered to be local to the class Bar block, because "A target occurring in a del statement is also considered bound" for the purpose of determining the scope of a name. But "unbound local variables are looked up in the global namespace" is not relevant, since del does not need to look up the value of the name in order to unbind it.
For good measure, we can experimentally confirm that a del statement signals to the interpreter that a name should be considered local.
a = 1
def foo():
a = 2
class Bar:
print(a)
del a
foo()
Result:
1
Traceback (most recent call last):
File "C:\Users\Kevin\Desktop\test.py", line 7, in <module>
foo()
File "C:\Users\Kevin\Desktop\test.py", line 4, in foo
class Bar:
File "C:\Users\Kevin\Desktop\test.py", line 6, in Bar
del a
NameError: name 'a' is not defined
Here we see that print(a) successfully looks up the value of the local variable a, and then on the next line it crashes because del can't delete an unbound local variable.
A local variable of a scope is any name defined anywhere in this scope. Notably, the variable itself is local, not the value assigned to it - a local variable can exist before or regardless of assignment.
>>> def foo(): # new function scope
... a = 3 # local variable `a`
... b: int # local variable `b`
... c = 3 # local variable `c`
... del c
... print(x)
... x = 3 # local variable `x`
... foo()
UnboundLocalError: local variable 'x' referenced before assignment
An unbound local variable is such a local variable with no value bound to it. In the above example, all of b, c and x are unbound at some point.
Neither of your examples access an unbound local variable. Both lookup the name a, but never assign to it.
In a function block, referencing unbound local variables is an error, namely UnboundLocalError. It does not matter whether that name exists in an enclosing scope as well.
>>> x = 1
>>> def foo():
... b = x # local variable is looked up locally
... x = 2 # make `x` a local variable
... foo()
UnboundLocalError: local variable 'x' referenced before assignment
In a class block, referencing unbound local variables falls back to a lookup in the global scope. This may or may not succeed.
>>> x = 1
>>> class Foo:
... b = x # local variable is looked up locally *or globally*
... x = 2 # make `x` a local variable
... print(Foo.b, Foo.x)
1 2
>>> class Foo:
... b = y # local variable is looked up locally *or globally*
... y = 2 # make `y` a local variable
... print(Foo.b, Foo.y)
NameError: name 'y' is not defined
I think I can make a supplement.
Python pre-computes which frame contains each name before executing the body of the function.
This means such phenomenon:
In [1]: a = 1
In [2]: def test():
...: print(a)
...:
In [3]: test()
1
In [4]: def test():
...: print(a)
...: a = 1
...:
In [5]: test()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-5-fbd55f77ab7c> in <module>
----> 1 test()
<ipython-input-4-a08051373573> in test()
1 def test():
----> 2 print(a)
3 a = 1
4
UnboundLocalError: local variable 'a' referenced before assignment
In [6]:
Error local variable 'a' referenced before assignment means Python pre-computes that function test frame has a local variable named a, we have to first assign one object to a and then reference it later.

Scope of variables in python

I just come across a confusion ,let's consider the below 2 codes
first code:
def out(): #func1
print i
i=5
Output:5
Second:
def inc(): #func2
i=i+1
print i
i=5
When execiting the above programs ,func1 doesn't give any error but func2 gives an error...
error: var i referenced before assignment
I am confused that i is a local variable or global.If it is local variable then how func1 is accessing it and if it's global then why func2 is unable to access it?
That depends, when you assign a variable inside a function using the = operator, it will shadow any other outer scopes declaration of the variable and use local instead, unless it's declared global inside the function.
For example, your second try will work as you expected if you would do it like this:
def inc(): #func2
global i
i=i+1
print i
i=5
On the other side, if no assignment is performed inside a function, it will use outer scopes declaration, as you saw in your first try.
Also, if you use global i but no i is defined in outer scopes the function will raise a not defined exception as well.
You need to declare i as global in func2 to be able to modify it's value.
def func_2():
global i
i=i+1
print i
Without the global statement, you would be incrementing a variable local to func_2 without actually first giving it a value. And that's where your error comes from.
You can print the contents of global variables without declaring them global. You can also access mutable containers like lists and dictionaries without the global statment but strings, integers, floats and so forth cannot be modified without first making them global.
Examples:
>>> i = [1, 2, 3]
>>> def func_3():
... i.append(4)
... print i
>>> func_3()
[1, 2, 3, 4]
>>> i = "foo"
>>> def func_4()
... i = "bar"
... print i
>>> func_4()
"bar"
>>> print i
"foo"

In Python what is a global statement?

What is a global statement? And how is it used? I have read Python's official definition;
however, it doesn't make a lot of sense to me.
Every "variable" in python is limited to a certain scope. The scope of a python "file" is the module-scope. Consider the following:
#file test.py
myvariable = 5 # myvariable has module-level scope
def func():
x = 3 # x has "local" or function level scope.
Objects with local scope die as soon as the function exits and can never be retrieved (unless you return them), but within a function, you can access variables in the module level scope (or any containing scope):
myvariable = 5
def func():
print(myvariable) # prints 5
def func2():
x = 3
def func3():
print(x) # will print 3 because it picks it up from `func2`'s scope
func3()
However, you can't use assignment on that reference and expect that it will be propagated to an outer scope:
myvariable = 5
def func():
myvariable = 6 # creates a new "local" variable.
# Doesn't affect the global version
print(myvariable) # prints 6
func()
print(myvariable) # prints 5
Now, we're finally to global. The global keyword is the way that you tell python that a particular variable in your function is defined at the global (module-level) scope.
myvariable = 5
def func():
global myvariable
myvariable = 6 # changes `myvariable` at the global scope
print(myvariable) # prints 6
func()
print(myvariable) # prints 6 now because we were able
# to modify the reference in the function
In other words, you can change the value of myvariable in the module-scope from within func if you use the global keyword.
As an aside, scopes can be nested arbitrarily deeply:
def func1():
x = 3
def func2():
print("x=",x,"func2")
y = 4
def func3():
nonlocal x # try it with nonlocal commented out as well. See the difference.
print("x=",x,"func3")
print("y=",y,"func3")
z = 5
print("z=",z,"func3")
x = 10
func3()
func2()
print("x=",x,"func1")
func1()
Now in this case, none of the variables are declared at the global scope, and in python2, there is no (easy/clean) way to change the value of x in the scope of func1 from within func3. That's why the nonlocal keyword was introduced in python3.x . nonlocal is an extension of global that allows you to modify a variable that you picked up from another scope in whatever scope it was pulled from.
mgilson did a good job but I'd like to add some more.
list1 = [1]
list2 = [1]
def main():
list1.append(3)
#list1 = [9]
list2 = [222]
print list1, list2
print "before main():", list1, list2
>>> [1] [1]
main()
>>> [1,3] [222]
print list1, list2
>>> [1, 3] [1]
Inside a function, Python assumes every variable as local variable
unless you declare it as global, or you are accessing a global variable.
list1.append(2)
was possible because you are accessing the 'list1' and lists are mutable.
list2 = [222]
was possible because you are initializing a local variable.
However if you uncomment #list1 = [9], you will get
UnboundLocalError: local variable 'list1' referenced before assignment
It means you are trying to initialize a new local variable 'list1' but it was already referenced before,
and you are out of the scope to reassign it.
To enter the scope, declare 'list1' as global.
I strongly recommend you to read this even though there is a typo in the end.
a = 1
def f():
a = 2 # doesn't affect global a, this new definition hides it in local scope
a = 1
def f():
global a
a = 2 # affects global a
Basically it tells the interpreter that the variable its given should be modified or assigned at the global level, rather than the default local level.
You can use a global variable in other functions by declaring it as global in each function that modifies it
Python wants to make sure that you really know that's what you're playing with by explicitly requiring the global keyword.
See this answer

Categories

Resources