令人困惑的范围变化 - 发生了什么?

时间:2011-07-26 15:49:03

标签: python

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

def 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

为什么第二个失败,因为唯一的区别是在打印语句之后的赋值?我对此非常困惑。

2 个答案:

答案 0 :(得分:8)

问题是Python希望你是明确的,你想要隐含。 Python使用的execution model将名称绑定到最近的可用封闭范围。

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()

没有(据我所知)在Python 2.x中使用范围的方法 - 你有globals()locals() - 但是全局范围和本地范围之间的任何范围无法访问(如果不是这样,我需要更正)。

但是,您可以将局部变量value传递到内部本地范围:

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)

在Python 3中,您有了新的nonlocal语句,可用于引用包含范围(Thanks @Thomas K)。

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

答案 1 :(得分:0)

这应该解决它:

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