首页 > 解决方案 > Python内部方法无法从外部方法获取变量

问题描述

下面的代码:

def cycle(f1, f2, f3):
    """Returns a function that is itself a higher-order function.

    >>> def add1(x):
    ...     return x + 1
    >>> def times2(x):
    ...     return x * 2
    >>> def add3(x):
    ...     return x + 3
    >>> my_cycle = cycle(add1, times2, add3)
    >>> identity = my_cycle(0)
    >>> identity(5)
    5
    >>> add_one_then_double = my_cycle(2)
    >>> add_one_then_double(1)
    4
    >>> do_all_functions = my_cycle(3)
    >>> do_all_functions(2)
    9
    >>> do_more_than_a_cycle = my_cycle(4)
    >>> do_more_than_a_cycle(2)
    10
    >>> do_two_cycles = my_cycle(6)
    >>> do_two_cycles(1)
    19
    """
    "*** YOUR CODE HERE ***"
    def execution(n):
        def inner(x):
            result = x
            while (n > 0):
                n = n - 1
                if (n >= 0):
                    result = f1(result)
                n = n - 1
                if (n >= 0):
                    result = f2(result)
                n = n - 1
                if (n >= 0):
                    result = f3(result)
            return result
        return inner
    return execution

在终端运行测试

$ python -m doctest xx.py

得到错误:

UnboundLocalError: local variable 'n' referenced before assignment

我认为方法中n使用的变量inner可以从外部方法中获取execution,就像在运行时一样,execution必须先调用才能inner调用方法,所以变量n必须已经初始化。我在这里犯了什么错误?是python 3.8.1我用的。

标签: pythonhigher-order-functions

解决方案


发生了什么,为什么?基于变量范围,您希望在外部范围(如果未定义)中查找变量并且它确实有效,试试这个:

def o(n):
    def i():
        print("now in inner", n)
    print("passed to outer", n)
    i()

o(42)

现在,如果您在内部范围内定义同名变量,它将(在该范围内)隐藏外部范围内的变量,您可以为其分配任何值,您可以访问它,这一切都发生在其范围内:

def o(n):
    def i():
        n = "in"
        print("now in inner", n)
    print("passed to outer", n)
    i()
    print("back in outer", n)

o(42)

那么为什么你会看到UnboundLocalError异常呢?因为如果在该范围内分配,python 将考虑其范围内的任何本地变量,如果在此类分配之前引用它,则不会在外部范围内访问它,而是认为尚未在本地分配:

def o(n):
    def i():
        print("now in inner", n)
        n = "in"
    print("passed to outer", n)
    i()
    print("back in outer", n)

o(42)

如果您nonlocal按照评论中的建议添加语句,错误就会消失,因为变量正在访问封闭范围而不是被视为本地,但这也意味着任何更改/(重新)分配也会影响外部范围,并且(尤其是在更大的程序中)可能会令人惊讶和困惑:

def o(n):
    def i():
        nonlocal n
        print("now in inner", n)
        n = "in"
    print("passed to outer", n)
    i()
    print("back in outer", n)

o(42)

为了使相关位更紧密并明确关系,最好将变量的值传递给内部函数,执行它要执行的任何逻辑并让它返回结果:

def o(n):
    def i(inner_n):
        print("now in inner", n)
        inner_n += 1
        return inner_n
    print("passed to outer", n)
    print("i() returned", i(n))
    print("back in outer", n)

o(42)

指向文档

以下构造绑定名称: ... 如果出现在分配中,则作为标识符的目标 ...

如果名称绑定在块中,则它是该块的局部变量,除非声明为nonlocalor global

或者如前所述,赋值可能是该块中的最后一个操作,但这意味着该变量始终被视为局部变量(除非明确告知不要这样做)。


推荐阅读