How references to variables are resolved in Python

后端 未结 3 414
無奈伤痛
無奈伤痛 2020-11-29 19:00

This message is a a bit long with many examples, but I hope it will help me and others to better grasp the full story of variables and attribute lookup in Python 2.7.

3条回答
  •  -上瘾入骨i
    2020-11-29 19:44

    In two words, the difference between example 5 and example 6 is that in example 5 the variable x is also assigned to in the same scope, while not in example 6. This triggers a difference that can be understood by historical reasons.

    This raises UnboundLocalError:

    x = "foo"
    def f():
        print x
        x = 5
    f()
    

    instead of printing "foo". It makes a bit of sense, even if it seems strange at first: the function f() defines the variable x locally, even if it is after the print, and so any reference to x in the same function must be to that local variable. At least it makes sense in that it avoids strange surprizes if you have by mistake reused the name of a global variable locally, and are trying to use both the global and the local variable. This is a good idea because it means that we can statically know, just by looking at a variable, which variable it means. For example, we know that print x refers to the local variable (and thus may raise UnboundLocalError) here:

    x = "foo"
    def f():
        if some_condition:
            x = 42
        print x
    f()
    

    Now, this rule doesn't work for class-level scopes: there, we want expressions like x = x to work, capturing the global variable x into the class-level scope. This means that class-level scopes don't follow the basic rule above: we can't know if x in this scope refers to some outer variable or to the locally-defined x --- for example:

    class X:
        x = x     # we want to read the global x and assign it locally
        bar = x   # but here we want to read the local x of the previous line
    
    class Y:
        if some_condition:
            x = 42
        print x     # may refer to either the local x, or some global x
    
    class Z:
        for i in range(2):
            print x    # prints the global x the 1st time, and 42 the 2nd time
            x = 42
    

    So in class scopes, a different rule is used: where it would normally raise UnboundLocalError --- and only in that case --- it instead looks up in the module globals. That's all: it doesn't follow the chain of nested scopes.

    Why not? I actually doubt there is a better explanation that "for historical reasons". In more technical terms, it could consider that the variable x is both locally defined in the class scope (because it is assigned to) and should be passed in from the parent scope as a lexically nested variable (because it is read). It would be possible to implement it by using a different bytecode than LOAD_NAME that looks up in the local scope, and falls back to using the nested scope's reference if not found.

    EDIT: thanks wilberforce for the reference to http://bugs.python.org/issue532860. We may have a chance to get some discussion reactivated with the proposed new bytecode, if we feel that it should be fixed after all (the bug report considers killing support for x = x but was closed for fear of breaking too much existing code; instead what I'm suggesting here would be to make x = x work in more cases). Or I may be missing another fine point...

    EDIT2: it seems that CPython did precisely that in the current 3.4 trunk: http://bugs.python.org/issue17853 ... or not? They introduced the bytecode for a slightly different reason and don't use it systematically...

提交回复
热议问题