开发者

Confusing change of scope - what's going on?

def Test(value):
    def innerFunc():
        print value
    innerFunc()

def开发者_如何学JAVA TestWithAssignment(value):
    def innerFunc():
        print value
        value = "Changed value"
    innerFunc()

Test("Hello 1")
# Prints "Hello 1"

TestWithAssignment("Hello 2")
# Throws UnboundLocalError: local variable 'value' referenced before assignment
# on the "print value" line

Why does the second one fail, given that the only difference is an assignment which comes after the print statement? I am pretty confused about this.


The issue is that Python wants you to be explicit and you want to be implicit. The execution model that Python uses binds names to the nearest available enclosing scope.

def Test(value):
    # Local Scope #1
    def innerFunc():
        # Local Scope #2
        print value 
        # No immediate local in Local Scope #2 - check up the chain
        # First find value in outer function scope (Local Scope #1).
        # Use that.
    innerFunc()

def TestWithAssignment(value):
    # Local Scope #1
    def innerFunc():
        # Local Scope #2
        print value 
        # Immediate local variable found in Local Scope #2.
        # No need to check up the chain.
        # However, no value has been assigned to this variable yet.
        # Throw an error.
        value = "Changed value"
    innerFunc()

There is not (as far as I know) a way to walk up the scope in Python 2.x - you have globals() and locals() - but any scopes between the global and the local scope cannot be accessed (if this is not true, I'd love to be corrected).

However, you can pass the local variable value into your inner local scope:

def TestWithAssignment(value):
    def innerFunc(value):
        print value 
        # Immediate local **and assigned now**.
        value = "Changed value"
        # If you need to keep the changed value
        # return value
    innerFunc(value)
    # If you need to keep the changed value use:
    # value = innerFunc(value)

In Python 3 you have the new nonlocal statement that can be used to refer to the containing scope (Thanks @Thomas K).

def TestWithAssignment(value):
    def innerFunc():
        nonlocal value
        print value 
        value = "Changed value"
    innerFunc()


This should fix it:

def Test(value):
    def innerFunc(value):
        print value
    innerFunc(value)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜