Online Book Reader

Home Category

Learning Python - Mark Lutz [238]

By Root 1754 0
scope into lambdas, just as for defs. For instance, the following works on all Python releases:

def func():

x = 4

action = (lambda n, x=x: x ** n) # Pass x in manually

return action

Because lambdas are expressions, they naturally (and even normally) nest inside enclosing defs. Hence, they are perhaps the biggest beneficiaries of the addition of enclosing function scopes in the lookup rules; in most cases, it is no longer necessary to pass values into lambdas with defaults.

Scopes versus defaults with loop variables

There is one notable exception to the rule I just gave: if a lambda or def defined within a function is nested inside a loop, and the nested function references an enclosing scope variable that is changed by that loop, all functions generated within the loop will have the same value—the value the referenced variable had in the last loop iteration.

For instance, the following attempts to build up a list of functions that each remember the current variable i from the enclosing scope:

>>> def makeActions():

... acts = []

... for i in range(5): # Tries to remember each i

... acts.append(lambda x: i ** x) # All remember same last i!

... return acts

...

>>> acts = makeActions()

>>> acts[0]

at 0x012B16B0>

This doesn’t quite work, though—because the enclosing scope variable is looked up when the nested functions are later called, they all effectively remember the same value (the value the loop variable had on the last loop iteration). That is, we get back 4 to the power of 2 for each function in the list, because i is the same in all of them:

>>> acts[0](2) # All are 4 ** 2, value of last i

16

>>> acts[2](2) # This should be 2 ** 2

16

>>> acts[4](2) # This should be 4 ** 2

16

This is the one case where we still have to explicitly retain enclosing scope values with default arguments, rather than enclosing scope references. That is, to make this sort of code work, we must pass in the current value of the enclosing scope’s variable with a default. Because defaults are evaluated when the nested function is created (not when it’s later called), each remembers its own value for i:

>>> def makeActions():

... acts = []

... for i in range(5): # Use defaults instead

... acts.append(lambda x, i=i: i ** x) # Remember current i

... return acts

...

>>> acts = makeActions()

>>> acts[0](2) # 0 ** 2

0

>>> acts[2](2) # 2 ** 2

4

>>> acts[4](2) # 4 ** 2

16

This is a fairly obscure case, but it can come up in practice, especially in code that generates callback handler functions for a number of widgets in a GUI (e.g., button-press handlers). We’ll talk more about defaults in Chapter 18 and lambdas in Chapter 19, so you may want to return and review this section later.[39]

Arbitrary scope nesting

Before ending this discussion, I should note that scopes may nest arbitrarily, but only enclosing function def statements (not classes, described in Part VI) are searched:

>>> def f1():

... x = 99

... def f2():

... def f3():

... print(x) # Found in f1's local scope!

... f3()

... f2()

...

>>> f1()

99

Python will search the local scopes of all enclosing defs, from inner to outer, after the referencing function’s local scope and before the module’s global scope or built-ins. However, this sort of code is even less likely to pop up in practice. In Python, we say flat is better than nested—except in very limited contexts, your life (and the lives of your coworkers) will generally be better if you minimize nested function definitions.

* * *

[39] In the section Function Gotchas at the end of this part of the book, we’ll also see that there is an issue with using mutable objects like lists and dictionaries for default arguments (e.g., def f(a=[]))—because defaults are implemented as single objects attached to functions, mutable defaults retain state from call to call, rather then being initialized anew on each call. Depending on whom you ask, this is either considered a feature that supports state retention, or a strange wart on the language. More on this

Return Main Page Previous Page Next Page

®Online Book Reader