简体   繁体   中英

Python scope, functions, blocks and non-local

I am confused about scope. What, if anything, is the difference between assigning a variable 'within a function' and assigning one within an indented block? I have read many places that if and try blocks do not create, or have, their own scope, but I have also read that the scope of a variable is the innermost block where it is defined. I googled but was not able to find an example of nonlocal inside an if or try block.

def sixdig2iso(pathfrom):
    os.chdir(pathfrom)
    filelist = os.listdir()
    nonlocal xfrs
    xfrs = 0

PyCharm says nonlocal variable 'xfrs' must be bound in an outer function scope Isn't this the outermost part of this function? Then what's the problem? Is the outermost part of this function?= an outer function? Even if the scopes of each are different from the inner parts of those same functions?!

if xfrs == 0:
    restofit = frs[1:]
    try:
        convert = datetime.strptime(mm, '%m%d%y')
    except ValueError as e:
        logger.info(f"For {filename}, mm is: {mm} - and the error is: {e}")
        count_err += 1
    ender = ' '.join(restofit)
    fronter = str(convert.date())

PyCharm says the 2nd convert 'might' be used before assignment

I tried making an inner function

def sixdig2iso(pathfrom):
    """Converts six digit dates into proper datetime format in place."""
    os.chdir(pathfrom)
    filelist = os.listdir()
    nonlocal xfrs
    xfrs = 0
    def blockscope():

But PyCharm gives me the same "nonlocal variable 'xfrs' must be bound in an outer function scope" warning.

UPDATE My response is too long for a comment.

  1. “We have to guess because you didn't provide a complete example” I can never seem to get the balance between 'not enough' and 'too much' information for these questions. I probably didn't think the part you say is missing was relevant, which goes to my understanding of the problem in the first place.

  2. “ it doesn't matter how many nestings of function you create inside this function, nonlocal only looks outward.“ See, I didn't know that. And I infer, then, it only looks 'upward', too, right?

  3. “As.strptime() might fail with an exception, convert may end up not having been assigned a value, as you did not initialise convert outside the try block. Ok, good, that is very helpful. I didn't realize (and PyCharm does not explain as you just did) this is what PyCharm was talking about. But this is also why I was confused about the 'scope' of a try block.

In the first example you give, xfrs is only defined in the function you've provided as an example. We have to guess because you didn't provide a complete example, but the message from PyCharm suggests that you did not define this function inside another function that already had such an identifier defined in it and there's no xfrs in the global scope either.

In the second example, you assign to convert in the try section of a try.. except block. As .strptime() might fail with an exception, convert may end up not having been assigned a value, as you did not initialise convert outside the try block. So, PyCharm is correct (again, we have to assume as you did not provide a complete example.

Finally, in the third example, you start defining a function inside the function, but still apply nonlocal to a variable in the sixdig2iso() scope - it doesn't matter how many nestings of function you create inside this function, nonlocal only looks outward.

A typical use of nonlocal is as @Carcigenicate provides in their link (some modifications here):

x = 0


def outer():
    x = 1

    def inner():
        nonlocal x
        x += 1
        return x

    return x, inner


v, f = outer()
print(x, v, f())

The function returned by outer() produces 2 when called, as its non-local variable x of inner() is the same as the local variable x of outer() , starting at 1 and having 1 added as the function is called.

You can tell that is what happens, as the value returned by outer() is 1 , but calling the returned function f() returns 2 . All the time, the global x is untouched.

Try changing nonlocal to global and you'll find the the result changes from:

0 1 2

To:

0 1 1

I hope that helps explain what is going on with nonlocal .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM