Non-Local Assignment

  • 在函数内部创建的变量,只在自己的 Frame 里

  • 对于高阶函数,内部函数想要 引用/改变 parent frame 的变量值,则无法进行

  • nonlocal 声明变量使其绑定为 parent frame 的变量

def make_withdraw(balance):
    "Return a withdraw function with a starting balance."
    def withdraw(amount):
        nonlocal balance # declare the name "balance" nonlocal
        if amount > balance:
            return "Insufficient funds"
        balance -= amount
        return balance
    return withdraw

withdraw = make_withdraw(100)
withdraw(25)
withdraw(25)
wtihdraw(60)

Non-Local 细节

  • 将来对该 name 的赋值 将更改 其在绑定该 name 的当前环境中,第一个非本地框架(first non-local framework)中预先存在的绑定

  • 该 name 要已经被使用过了(已经存在)

  • 该 name 不能与 local scope 的 name 冲突

状态(x=2)

影响

没有nonlocal,x 没有在本地绑定

在当前环境的第一个 frame 中,创建一个 x 到对象 2 的新绑定

没有nonlocal,x 已经在本地绑定过

在当前环境的第一个 frame 中,将 x 重新绑定到对象 2

有nonlocal x,x 已经在 non-local frame 绑定过

在当前环境的第一个 non-local frame 中,将 x 重新绑定到对象 2

有nonlocal x,x 没有在 non-local frame 绑定过

语法错误

有nonlocal x,x 已经在 non-local frame 绑定过, x也在本地绑定过

语法错误

Python particulars(细节)

  • python 在执行方法内部前 -> 预先计算 每个 name 属于 哪个 frame

  • 在 function 内部,单一 name 的所有实例必须指向同一个框架

def make_withdraw(balance):
    """Return a withdraw function with a starting balance."""
    def withdraw(amount):
        if amount > balance:
            return 'Insufficient funds'
        balance = balance - amount  # 执行前计算,得知 balance 是本地变量
        return balance
    return withdraw
def make_withdraw(balance):
    """Return a withdraw function with a starting balance."""
    def withdraw(amount):
        if amount > balance:
            return 'Insufficient funds'
        # balance = balance - amount # 如果去掉,可以正常执行,因为这个 name 指向前一个 frame
        return balance
    return withdraw

其他可选的方法

  • 用可变值,如列表

def make_withdraw_list(balance):
    b = [balance]
    def withdraw(amount):
        if amount > b[0]:
            return 'Insufficient funds'
        b[0] = b[0] - amount
        return b[0]
    return withdraw

突变会导致 函数的引用透明性(referential transparency) 丢失

  • 函数的返回值只依赖于其输入值,这种特性就称为引用透明性

  • Mutation operations 违反了引用透明度的条件

    • 因为它们不仅仅是返回一个值,而是改变了环境

Last updated

Was this helpful?