I've read almost all the other questions about the topic, but my code still doesn't work.
I think I'm missing something about python variable scope.
Here is my code:
PRICE_RANGES = {
64:(25, 0.35),
32:(13, 0.40),
16:(7, 0.45),
8:(4, 0.5)
}
def get_order_total(quantity):
global PRICE_RANGES
_total = 0
_i = PRICE_RANGES.iterkeys()
def recurse(_i):
try:
key = _i.next()
if quantity % key != quantity:
_total += PRICE_RANGES[key][0]
return recurse(_i)
except StopIteration:
return (key, quantity % key)
res = recurse(_i)
And I get
"global name '_total' is not defined"
I know the problem is on the _total
assignment, but I can't understand why.
Shouldn't recurse()
have access to the parent function's variables?
Can someone explain to me what I'm missing about python variable scope?
In Python 3, you can use the nonlocal
statement to access non-local, non-global scopes.
The nonlocal
statement causes a variable definition to bind to a previously created variable in the nearest scope. Here are some examples to illustrate:
def sum_list_items(_list):
total = 0
def do_the_sum(_list):
for i in _list:
total += i
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
The above example will fail with the error: UnboundLocalError: local variable 'total' referenced before assignment
Using nonlocal
we can get the code to work:
def sum_list_items(_list):
total = 0
def do_the_sum(_list):
# Define the total variable as non-local, causing it to bind
# to the nearest non-global variable also called total.
nonlocal total
for i in _list:
total += i
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
But what does "nearest" mean? Here is another example:
def sum_list_items(_list):
total = 0
def do_the_sum(_list):
# The nonlocal total binds to this variable.
total = 0
def do_core_computations(_list):
# Define the total variable as non-local, causing it to bind
# to the nearest non-global variable also called total.
nonlocal total
for i in _list:
total += i
do_core_computations(_list)
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
In the above example, total
will bind to the variable defined inside the do_the_sum
function, and not the outer variable defined in the sum_list_items
function, so the code will return 0
.
def sum_list_items(_list):
# The nonlocal total binds to this variable.
total = 0
def do_the_sum(_list):
def do_core_computations(_list):
# Define the total variable as non-local, causing it to bind
# to the nearest non-global variable also called total.
nonlocal total
for i in _list:
total += i
do_core_computations(_list)
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
In the above example the nonlocal assignment traverses up two levels before it locates the total
variable that is local to sum_list_items
.