Python Nested Function Variable Assignment [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 9 years ago.
I'm trying to do something along the following lines in python3:
i = 1337
def g():
print(i)
i = 42
g()
but get the following error
UnboundLocalError: local variable 'i' referenced before assignment
I think I understand what the error message means, but why is it the case? Is there any way to circumvent this?

In two words - when a given variable name is not assigned a value within a function then references to the variable will be looked up. Use global - and in such a case python will look for i in global scope:
i = 1337
def g():
global i
print i
i = 42
g()
You can read more on variable scopes in PEP-0227

If you really really want to do it that way, you'll need to get i from the global scope.
def g():
global i
print i
i = 42
However, generally you would be much better off changing how your code works to not require globals. Depending on how you are using it, that could be as simple as passing in i as a parameter and returning the changed value.

An example of Keeyai's suggestion of passing in i as a parameter:
i = 1337
def g(i):
print(i)
i = 42
g(i)
However, you never use the new value of i, so perhaps something like this makes more sense:
def g (i):
i = 42
return i
i = 1337
print g(i)

Related

Python scope, functions, blocks and non-local [duplicate]

This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 5 months ago.
I am confused about scope.
What, if anything, is the difference between assigning a variable 'within a function' and assigning one within an
indented block? I have read many places that if and try blocks do not create, or have, their own scope, but I have also
read that the scope of a variable is the innermost block where it is defined.
I googled but was not able to find an example of nonlocal inside an if or try block.
def sixdig2iso(pathfrom):
os.chdir(pathfrom)
filelist = os.listdir()
nonlocal xfrs
xfrs = 0
PyCharm says nonlocal variable 'xfrs' must be bound in an outer function scope
Isn't this the outermost part of this function? Then what's the problem?
Is the outermost part of this function != an outer function? Even if the scopes of each are different from the inner parts of those same functions?!
if xfrs == 0:
restofit = frs[1:]
try:
convert = datetime.strptime(mm, '%m%d%y')
except ValueError as e:
logger.info(f"For {filename}, mm is: {mm} - and the error is: {e}")
count_err += 1
ender = ' '.join(restofit)
fronter = str(convert.date())
PyCharm says the 2nd convert 'might' be used before assignment
I tried making an inner function
def sixdig2iso(pathfrom):
"""Converts six digit dates into proper datetime format in place."""
os.chdir(pathfrom)
filelist = os.listdir()
nonlocal xfrs
xfrs = 0
def blockscope():
But PyCharm gives me the same "nonlocal variable 'xfrs' must be bound in an outer function scope" warning.
UPDATE
My response is too long for a comment.
“We have to guess because you didn't provide a complete example”
I can never seem to get the balance between ‘not enough’ and ‘too much’ information for these questions. I probably didn’t think the part you say is missing was relevant, which goes to my understanding of the problem in the first place.
“ it doesn't matter how many nestings of function you create inside this function, nonlocal only looks outward.“
See, I didn’t know that. And I infer, then, it only looks ‘upward’, too, right?
“As .strptime() might fail with an exception, convert may end up not having been assigned a value, as you did not initialise convert outside the try block. “
Ok, good, that is very helpful. I didn’t realize (and PyCharm does not explain as you just did) this is what PyCharm was talking about. But this is also why I was confused about the ‘scope’ of a try block.
In the first example you give, xfrs is only defined in the function you've provided as an example. We have to guess because you didn't provide a complete example, but the message from PyCharm suggests that you did not define this function inside another function that already had such an identifier defined in it and there's no xfrs in the global scope either.
In the second example, you assign to convert in the try section of a try .. except block. As .strptime() might fail with an exception, convert may end up not having been assigned a value, as you did not initialise convert outside the try block. So, PyCharm is correct (again, we have to assume as you did not provide a complete example.
Finally, in the third example, you start defining a function inside the function, but still apply nonlocal to a variable in the sixdig2iso() scope - it doesn't matter how many nestings of function you create inside this function, nonlocal only looks outward.
A typical use of nonlocal is as #Carcigenicate provides in their link (some modifications here):
x = 0
def outer():
x = 1
def inner():
nonlocal x
x += 1
return x
return x, inner
v, f = outer()
print(x, v, f())
The function returned by outer() produces 2 when called, as its non-local variable x of inner() is the same as the local variable x of outer(), starting at 1 and having 1 added as the function is called.
You can tell that is what happens, as the value returned by outer() is 1, but calling the returned function f() returns 2. All the time, the global x is untouched.
Try changing nonlocal to global and you'll find the the result changes from:
0 1 2
To:
0 1 1
I hope that helps explain what is going on with nonlocal.

How to set variable within function def in python? [duplicate]

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)
UnboundLocalError: local variable … referenced before assignment [duplicate]
(2 answers)
Closed 2 years ago.
I have a simple code like this:
temp = 100
def my_fun():
temp += 10
return temp
After I call this function my_fun() I get an error
local variable 'temp' referenced before assignment
What's wrong with my code? I set temp before I call it. But still an error.
Thanks to all.
Best would be to pass it in:
def my_fun(temp):
temp += 10
return temp
temp = 100
temp = my_fun(temp)
But if you really want to access it from the outer scope, then use:
global temp
Edit: I see you amended your question - the reason for the error is the scope of the var. Within the function that variable only exists at the function level, and since you've not actually assigned it or passed it in, it doesn't exist when you try and increment it.

Difference between two variable assignments in function scope modifying global vars [duplicate]

This question already has answers here:
Another UnboundLocalError in Python2.7 [duplicate]
(2 answers)
Closed 3 years ago.
What's the difference between doing:
m={}
i='a'
def change():
m['a'] = i
i = 'b'
Which raises an attribute error:
>>> change()
UnboundLocalError: local variable 'i' referenced before assignment
And:
m={}
i='a'
def change():
m['a'] = i
Which evaluates without an error.
>>> change()
>>> m
{'a': 'a'}
(Finally, a question about this question -- when is it appropriate to use the "yellow background" in the questions?)
This is answered in depth in the docs:
This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope. Since the last statement in foo assigns a new value to x, the compiler recognizes it as a local variable. Consequently when the earlier print(x) attempts to print the uninitialized local variable and an error results.
And the yellow background is stylistic but is generally used for quotes from somewhere but also can be used for any reason you want to break that text away from the main body or text or code.

Scope in Python 3.6.And the Error [duplicate]

This question already has answers here:
Function not changing global variable
(4 answers)
Closed 5 years ago.
How does the code below give the output as None?
def funct(x):
x=7
x=11
x=test(x)
print(x)
Here is another code snippet:-
def func():
print (x)
x = 90
x = 1
func()
The output for this should be 90! The scope is searched as Local ,Enclosed , Global ,Build-in .Either x should here be searched as local or global
Please explain.
x here is not a global variable in the scope of the functions, as functions naturally create their own namespaces, which do not include any outer variables not passed in as a parameter.
There are many issues with your code, including the order of function calling, and the order of the operations inside the functions; but to answer your question in the broadest way possible, in order for you to access the x variable defined outside of your functions, in a greater scope that is, you need to reference its namespace, by prepending global x inside the body of each of your functions.
Read up on Python variables and scope, and recheck the other errors in your code I have stated above.
The first code snippet returns None for the simple fact that you didn't return any value from the function. You defined x as a local parameter, not a global variable. Since you didn't return any value, your call test(x) (which does not match the function name of funct), will become a value of None. This is clearly defined in the Python documentation. To get the local value back to your main program, try this:
test(x):
x = 7
return x
x = 11
x = test(x)
print(x)
Also, please note that your initial value of 11 is entirely ignored in the main program, and that your function ignores the value it's given. You should shorten this example to
func():
return 7
print(func())
Your second example will print the external value of 1 because you have not defined a local variable x at that point, and a function is allowed to reference global variables.
However, when you assign a value in the next, you create a local variable -- you have not declared x to be global, so you can't assign to the x in the main program.
Again, you do not return any value. Therefore, back in the main program, func() evaluates to None.
Does that clear up what happened?

UnboundLocalError: local variable 'r' referenced before assignment [duplicate]

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 9 years ago.
I'm having an issue with variable and function. Here is a simple code:
r = 0
list = ['apple','lime','orange']
def list_list(x):
for i in x:
r +=1
print r
list_list(list)
Error:
UnboundLocalError: local variable 'r' referenced before assignment
I know it must be something simple. I started to do my script using functions instead straight code.
You should rewrite your function to take r as an argument if you want to define it outside of your function:
def my_func(some_list, r=0):
# do some stuff
Basically, you have a problem with scope. If you need r outside of the function, just return it's value in a tuple:
def my_func(some_list, r=0):
# do some stuff
return new_list, r
my_list = [1,2,3,4,5]
different_list, my_outside_r = my_func(some_list, 0)
The r within the function isn't the same as the one outside the function, so it hasn't been set yet.
You shoudld put r = 0 inside the function. But if you want the length of the list just use len(list)
Also try to avoid naming variables same as builtin names like list.

Categories