I have one outer function and 2 inner functions.
def outer():
x = 'hello'
def inner1():
def inner2():
nonlocal x
x = 'python'
inner2()
print(x)
outer()
Please help me understand why the above code is not printing the value of x.
As per my understanding, it should print "hello"
Your code calls outer(), which in turn executes only one statement:
x = 'hello'
As it stands, the code in your question will print nothing.
If you were to add the line print(x) after the call to outer(), it would indeed print "hello", as you have suggested.
If you were to instead add the line inner1() to call the function by that name which is defined inside outer(), then inner1() would in turn call inner2() which would in turn cause x = 'python' to execute, and this would change the value of x and (thanks to the nonlocal x line within inner2()) the statement print(x) within inner1() would cause the code to print "python".
Related
My problem is simple.
This code,
def first():
x = "hello"
def second():
global x
x = "goodbye"
second()
first()
does not work, since globalizing a variable declared inside a function isn't valid. If it was just one function I know it would, but how could I get this to work like this?
Problem :
The problem is there are two different x variables getting confused. The x in second() is global and can be printed out after running after running your code. The problem is the first x is considered a local in first(). You can check it on your own by copy-pasting the following code in different places to understand how the code considers the variable:
if 'x' in locals():
print("local")
elif 'x' in globals():
print("global")
else:
print("unedfined")
Solution 1:
Always having x as a global by adding global x right on the line after def first() (and keeping it after def second())
Solution 2:
Accepting not having globals. Instead you can return x at the end of your functions and assigning an other variable (that could have the same name) to the returned value of the function eg.x = second(). Then using that variable as an argument eg. def first(x):
Hope it helps.
You need to declare a variable as global before you write to it in each of the functions. Like so:
def first():
global x
x = "hello"
def second():
global x
x = "goodbye"
second()
first()
print(x)
# >>> goodbye
I'd recommend a different structure to your project though
What I understood, you can initialize x variable before the function and then assign value to it when you want like this:
x = ''
def first():
x = "hello"
def second():
x = "goodbye"
second()
first()
In Python, does a function just execute it’s code block & not store it unless we use a return statement?
When we print variables & expressions I understand we are printing values.
So I am thinking that a function performs it’s code block & then does not save that result unless we return it? Is this what’s happening in the computer?
Example 1
def add(a,b):
nums = a + b
print(add(2,4)+2)
Error
But when we use the return value statement it works
Example 2
def add(a,b):
nums = a + b
return nums
print(add(2,4) + 2)
Output: 8
The error was caused in the first example because the function just executed it’s code block & did not save the result therefore resulting in an error due to not being able to add None to an integer(2)?
&
It worked in example 2 because we saved the functions result with the return statement giving us an integer; Therefore allowing the print statement to print the result of the functions integer + the integer we added it to in the expression?
In python, functions are blocks of code that execute some logic of some sort (sometimes based on arguments passed into them and sometimes not). They are very broad and can do many different kinds of things depending on how they are constructed. I'm not exactly sure what you mean by "store the results" but hopefully some of the following explanation will help.
All variables created in a function are stored with the "local" scope, meaning that they are only existent when the function is running and are deleted the moment the function terminates. For example, in the following code, you cannot access the variable x after the function terminates:
def example():
x = 'Hello World'
print(x) #This prints: Hello World
example()
print(x) #This will give you a Reference error
If that is what you mean by "stores the results" then you are right: those results will not be stored. You can, however, declare a variable inside of a function to be a global variable, meaning that it can be accessed outside of the function too:
def example():
global x = 'Hello World'
print(x) #This prints: Hello World
example()
print(x) #This prints: Hello World
When you use the return statement in a function you are just telling the compiler that if a variable is set equal to a function call of said function, whatever follows the return statement is what that variable should be set equal to. However, simply returning a value does not "store" it. See the following code:
def example():
x = 'Hello World'
return x
example()
print(x) #This will still cause a reference error
x = example()
print(x) #This prints: Hello World
One final thing to note about the code above: as long as two variables are in different scopes, they can have the same name and not cause an error. The x inside the function is in a local scope and the x outside of the function is in the global scope which is why that does not cause an error.
Welcome to Stack Overflow. When I was learning programming, it helped me to think of calls to functions using an analogy to variables in math. In most languages, you can think of "substituting" the return value in for the function call, the same way you can substitute a literal number into a variable.
In math, you can do this:
m = 4
b = 2
y = m * x + b # Plug 4 and 2 in for "m" and "b"
y = 4 * x + 2
It's the same with value-returning functions:
def foo():
return 'bar'
>>> x = foo() # Plug the return value 'bar' in for "foo()"
>>> x
'bar'
In Python, when a function has no explicit return, the default return value is None. So:
def foo():
print('bar')
# No return, so Python implicitly returns None
>>> x = foo() # Plug the return value None in for "foo()"
'bar'
>>> x
None
the function define local variable even same name as global variable so when it executed if you don't return something or store the result in global variable the result not appears outside function
example
x = 10
def test():
x= 15
test()
print(x) # result 10
but if use global keyword you can access to global variable like this
x = 10
def test():
global x
x= 15
test()
print(x) #result 15
or if you return the value
x = 10
def test():
x= 15
return x
x = test()
print(x) #result 15
This code throws NameError: name 'x' is not defined":
def function():
global x
print(x)
function()
print(x)
However, this code works and prints "2" two times:
def function():
global x
x = 2
print(x)
function()
print(x)
My question is, what actually happens at the moment x is declared as global?
You have not defined x, resulting in the errors. Try and make the function have a parameter of x.
def function(x):
print(x)
Also, when you globalize a variable, its scope is not just within the function, but in every function/class.
Carden
def outside(x=1):
def printHam():
x = x+1
print x
return printHam
myfunc = outside(7)
myfunc()
This doesn't works gives error Local variable referenced before assignment error python
However this works
def outside(x=1):
def printHam():
print x + 1
return printHam
myfunc = outside(7)
myfunc()
Because you are assigning x in the first case, python will assume x is a local variable (which is the default). In the second case you aren't assigning it so it will check the global scope.
If you want this example to work, you have to pass the outer x into the inner function like so:
def outside(x=1):
def printHam(x=x):
x = x+1
print x
return printHam
That being said, this seems like a horribly contrived use case, so there's probably a better solution for your actual use case. But I can't tell you what it is without knowing more about what you're trying to do.
I am reading this article about decorator.
At Step 8 , there is a function defined as:
def outer():
x = 1
def inner():
print x # 1
return inner
and if we run it by:
>>> foo = outer()
>>> foo.func_closure # doctest: +ELLIPSIS
it doesn't print x. According to the explanation :
Everything works according to Python’s scoping rules - x is a local
variable in our function outer. When inner prints x at point #1 Python
looks for a local variable to inner and not finding it looks in the
enclosing scope which is the function outer, finding it there.
But what about things from the point of view of variable lifetime? Our
variable x is local to the function outer which means it only exists
while the function outer is running. We aren’t able to call inner till
after the return of outer so according to our model of how Python
works, x shouldn’t exist anymore by the time we call inner and perhaps
a runtime error of some kind should occur.
However, I don't really understand what the second paragraph means.
I understand inner() does get the value of x but why it doesn't print x out?
thanks
UPDATE:
Thanks all for the answers. Now I understand the reason.
the "return inner" is just a pointer to inner() but it doesn't get executed, that is why inner() doesn't print x as it is not called at all
I understand inner() does get the value of x but why it doesn't print
x out?
It doesn't print out anything because you've not called the inner function yet.
>>> def outer():
x = 1
def inner():
print x # 1
return inner
...
>>> func = outer()
>>> func
<function inner at 0xb61e280c>
>>> func()
1
This is called a closure, i.e even though the outer function is not in stack(finished executing) anymore but still the inner function that was returned from it remembers it's state.(i.e value of x)
>>> def outer():
x = 1
y = 2
def inner():
z=3
print x
return inner
...
>>> func = outer()
>>> func.func_code.co_freevars #returns the variables that were used in closure
('x',)
From the source code on how python decides it's a closure or not:
459 if len(code.co_freevars) == 0:
460 closure = NULL
461 else:
462 len(closure) == len(code.co_freevars)
In py3.x you can also modify the value of x using nonlocal statement inside inner function.
>>> def outer():
x = 1
def inner():
nonlocal x
x += 1
print (x)
return inner
...
>>> func = outer()
>>> func()
2
>>> func()
3
>>> func()
4
You are not calling inner. You have called outer, which returns inner, but without calling it. If you want to call inner, do foo() (since you assinged the result of outer() to the name foo).
The paragraph you quoted is sort of tangential to this issue. You say you already understand why inner gets the value of x, which is what that paragraph is explaining. Basically, if a local variable is used in a nested function, and that nested function is returned, the value of the variable is stored along with the returned function, even if the scope where that variable was defined in no longer active. Normally x would be gone after outer finished, because x is just local to outer. But outer returns inner, which still needs access to x. So x gets wrapped up into what's called a closure, so it can still be accessed by inner later on.