Reputation: 4298
I am new to Python so I am unsure about the difference in variable assignment before or after the function definition.
Specifically, the first example was adopted from Lutz's book.
def tester(start):
print("inside tester")
def nested(label):
print("inside nested")
print(label,nested.state)
nested.state += 1
print("done with nested")
nested.state = start
print("done with tester")
return nested
F = tester(0)
F('spam')
F.state
F.state
The objective of the code is to store the state information without using nonlocal
.
I am unsure what nested.state
means here. I am unsure because nested.state
is used inside nested()
function (i.e. nested.state +=1
) and outside nested()
function (i.e. nested.state = start
).
I modified the code above to see whether Python accepts assigning variable after function declaration for nested()
and to see whether there is any concept I am missing relating to function.variable
call (i.e. nested.state
call).
def tester(start):
def nested(label):
print(label, state)
state += 1 #replaced 'nested.state' with 'state' here
state = start #replaced 'nested.state' with 'state' here
return nested
F=tester(0)
F('spam')
F('ham')
Unfortunately, above code generates error local variable 'state' referenced before assignment
. This tells me that I am missing some concept about function.variable
(i.e. nested.state
).
Can someone please help me understand three things:
I. why it is that the code with nested.state
doesn't generate any error but state
does?
II. what does nested.state
mean? If nested.state
is a mechanism to access function's variables, why is it that the call inside nested()
function also uses nested.state
and not state
?
III. If nested.state
is a mechanism to access variable inside function, then why is it that PyCharm fails to show state
under dropdown when I type nested.
?
I'd appreciate any help. I research SO, and couldn't find any explanation on such problems.
Upvotes: 1
Views: 1812
Reputation: 1221
First, remember a += b
is the same as a = a + b
. So a
must exist before getting to the +=
.
Simply put, in the first example the function nested
has an attribute called state
(accessed by nested.state
). It is an attribute, which means that once you tell nested
that it has an attribute called state
(you are doing this in line 9 when nested.state = start
) it keep that attribute. So, in the first example nested.state
exists when you get to the +=
.
In the second example, you are declaring a variable called state
in tester
, and another variable called state
in nested
. The one in nested
could be called potato
for all that matters, because it is not the same variable. Therefore when you arrive to the +=
, the variable state
does not exist!
Upvotes: 0
Reputation: 2255
Actually, I think you're asking a question about scope in Python, ignoring your code, check this:
def scope_level_1():
variable = 'Scope_level_1'
def scope_level_2():
variable = 'Scope_level_2'
def core():
nonlocal variable
variable += '_TOUCHED_AND_MODIFIED_BY_CORE'
print(variable)
return core()
return scope_level_2()
scope_level_1()
# 'Scope_level_2_TOUCHED_AND_MODIFIED_BY_CORE'
Don't worry about the keyword nonlocal, treat it just as a declaring to make code more readable.
Upvotes: 0
Reputation: 22953
The reason the first code example worked is because it was assigning and referencing an attribute of the nested
function object. The key concept to understand here, is that Python allows you to assign new, arbitrary attributes to objects - including functions:
>>> def func(a, b):
return a + b
>>> func(1, 2)
3
>>> func.attr = 5
>>> func.attr
5
The first code example takes advantage of this fact by using the nested
function object to store the necessary state. This is the same concept as using any other object to store the state. It's particularly convenient, however, to use a function since it's readily available.
In the second example, a normal variable is used. Because of this, normal scoping rules apply which means simply that the state
variable defined in tester
is not the state
variable being referenced in nested
. Thus, an error is raised.
Upvotes: 1