A newbie quesiton: local variable in a nested funciton

Chris Angelico rosuav at gmail.com
Sat Dec 26 04:49:47 EST 2015


On Sat, Dec 26, 2015 at 8:07 PM,  <jfong at ms4.hinet.net> wrote:
> Thank you for the explanation. It reminds me to dig out something which seems I had been read before. It's about nested scope in the book "Learning Python" by Mark Lutz.
>
>  "An assignment (X = value) creates or changes the name X in the current local
> scope, by default. If X is declared global within the function, the assignment creates or changes the name X in the enclosing module's scope instead. If, on the other hand, X is declared  nonlocal within the function in 3.X (only), the assignment changes the name X in the closest enclosing function's local scope."
>

Yep! That's an accurate description of how assignment works.

One of the cool things about Python is that there are all sorts of
things that work _exactly_ the same way. Every one of these statements
is a form of assignment:

import json  # 1
from sys import argv  # 2
def testfiles(files): # 3, 4
    failures = 0 # 5
    for file in files:  # 6
        with open(file) as fp: # 7
            try: data = json.load(fp) # 8
            except JSONDecodeError as err: # 9
                failures += 1 # 10
    return failures
count = testfiles(argv) # 11

Okay, every one except the 'return' statement. :)

1: "import x" is basically the same as "x = __import__('x')".
2: "from x import y" is basically "y = __import__('x').y" (more or
less). This grabs "sys.argv" and assigns it to the name "argv".
3: Defining a function constructs a new function object and assigns it
to the name. This is like doing "testfiles = <magic>".
4: As the function gets called, a new scope is created, and inside
that scope, the interpreter does the equivalent of "files = <magic>",
where the magic snags a reference to whatever was used as the argument
(so this is basically "files = argv").
5: That's straight-forward assignment, right there.
6: A 'for' loop grabs an iterator, then repeatedly does "file =
next(iterator)" until there's nothing more to do.
7: A 'with' statement does some work, and then does "fp = <result of
that work>" if it has an 'as' clause.
8: Another straight-forward assignment, because I couldn't think of
anything better to use. (Normally you'd lay this out with 'try:' on a
separate line, but then I'd have had a line without any assignment at
all.)
9: Like a 'with' statement, 'except' assigns to its name. There's a
special case here, in that it also does 'del err' at the end of the
except block, to clean stuff up; but it's still just assignment.
10: Augmented assignment is assignment too. x+=1, x-=1, x*=1, etc, are
all assigning to x.
11: Another normal assignment, because otherwise the rest of the work
is pointless. :)

Every one of these follows the standard rules for assignment. For
instance, you could create a function that does a top-level import:

$ python3
Python 3.6.0a0 (default:6e114c4023f5, Dec 20 2015, 19:15:28)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def do_imports():
...     global os, sys, json
...     import os, sys, json
...
>>> do_imports()
>>> json
<module 'json' from '/usr/local/lib/python3.6/json/__init__.py'>

You wouldn't normally do this for standard modules like 'os' and
'sys', but if you have something huge to load up (like pandas, or
oauth2client), it might be convenient to use them globally, but load
them conditionally. Since 'import' is a statement, not a declaration,
you can do this!

Python's flexibility and simplicity are a huge part of why I love the
language so much.

ChrisA



More information about the Python-list mailing list