python中的 nonlocal 和 global

做 leetcode 1774时候遇到的一个bug

class Solution:
    def closestCost(self, baseCosts: List[int], toppingCosts: List[int], target: int) -> int:
        ans = min(baseCosts)
        if ans >= target:
            return ans

        def dfs(cur, temp):
            nonlocal ans
            # cur是 topping 的下标
            if abs(ans - target) < temp - target:
                return
            if abs(temp - target) < abs(ans - target):
                ans = temp
            if abs(temp - target) == abs(ans - target):
                ans = min(temp, ans)
            if abs(temp - target) == 0:
                return temp
            if cur == len(toppingCosts):
                return 
            dfs(cur + 1, temp)
            dfs(cur + 1, temp + toppingCosts[cur])
            dfs(cur + 1, temp + 2 * toppingCosts[cur])
        for i in baseCosts:
            dfs(0, i)
        return ans

刚开始写成global ans, 发现报错, 因为ans还是定义在外层的函数中, 并不是全局变量

贴一下博客解释
https://www.cnblogs.com/jwyqn/p/14584766.html
nonlocal 是 python 内置的关键字,其作用是可以在内层函数内声明一个外部函数的变量,它的功能与global 相似,nonlocal 本质上是介于 全局作用域和局部作用域之间的,它仅在函数的嵌套使用时才起作用。




global
global 是 python 内置的关键字 其作用是可以在函数内声明一个全局变量,在上一章我们说到了,在局部空间里不能直接修改全局作用域的变量,其实修改是可以的,只是需要事先声明,也就是要告诉解释器 这是一个全局变量,一会修改的时候你就到全局去找它吧。

在函数内部修改全局变量
实例1:

num = 0
def func():
    num += 1
    
func()

结果:UnboundLocalError: local variable 'count' referenced before assignment

原因:在局部修改全局变量 num 时没有事先声明 num 是一个全局变量。所以报错

该实例具体报错原因前面 Python作用域中将 Local 局部作用域中 实例2 的时候已经讲解过了,这里不再赘述

实例2:

num = 0
def func():
    num = 1
    print("in loclas ", num)  # 打印函数内部的 num
print("in globals ", num)  # 打印全局的 num
func()

结果:

in globals 0
in loclas 1
原因:func 里的变量 num 之所以结果是 1 并不是修改了全局变量,而是在局部名称空间里重新创建了一个 num 变量,并给其赋值 1 ,函数内部也就是局部作用域可以引用全局作用域的变量,但是不能直接修改。

实例3:

num = 0
def func():
    global num  # 声明一个全局变量
    num += 1
    print("in loclas ", num)  # 打印函数内部的 num
print("in globals ", num)  # 打印全局的 num
func()

结果:

in globals 0

in loclas 1

原因:在局部修改全局变量之前,先声明了这个变量的来源 global num 就是告诉解释器 变量 num 是一个全局变量,如果一会在函数里面有针对num 这个变量的修改操作就去全局名称空间里面寻找这个num

小结:

通过上面两个实例我们可以得出,Python 在局部可以引用全局变量 但是不能直接修改
Python 在 局部作用域要对一个全局作用域的变量进行修改或需要事先声明这是一个全局变量。
函数嵌套
Python 函数嵌套是指 一个函数里面再定义一个函数

def func1():
    x = 100
    def func2():
        print(x)
    func2()
func1()

结果:func1 >>> 100

这个就是函数的嵌套,我们先来看一下嵌套函数的执行顺序

这是详细版本

这是简化版本
你也可以理解为python程序在执行过程中是从上往下顺序执行的,如果遇到def function_name():python会直接跳过函数这段代码不会执行里面的代码
总之函数在Python程序中的执行顺序一定看得懂,不然后面有很多东西你会跟不上的。
nonlocal
nonlocal 是 python 内置的关键字,其作用是可以在内层函数内声明一个外部函数的变量,它的功能与global 相似,nonlocal 本质上是介于 全局作用域和局部作用域之间的,它仅在函数的嵌套使用时才起作用。

实例1:

def func1():
    count = 1
    def func2():
        count += 1
    func2()
func1()

结果:UnboundLocalError: local variable 'count' referenced before assignment

原因:原因跟上面 实例1 一样只不过不是全局变量而是 内层函数 修改外部函数前没有事先声明 python解释器在内层函数里找不到 count 变量就会直接报错

实例2:

def func1():
    count = 1
    def func2():
        count = 100
        print("in func2 ", count)  # 打印内层函数的count
    func2()
    print("in func1 ", count)  # 打印外层函数的count
func1()  

结果:

in func2 100
in func1 1
原因:内层函数与外层函数的关系就和全局和局部的关系一样,内层函数可以引用外层函数的变量,但是无法直接修改。

注意:func2 里的 count = 100 并不是修改 外部函数的 count 变量,当你在内层函数里写上变量名并给其赋值的时候,python如果看到局部名称空间里没有这个变量名称,它就会创建一个新的变量并赋值。

实例3:

def func1():
    count = 1
    def func2():
        nonlocal count
        count += 100
        print("in func2 ", count)
    func2()
    print("in func1 ", count)
func1()

结果:

in func2 101
in func1 101
原因:因为在修改变量 count 之前 事先声明了这个 count 是来自外层函数的 count ,解释器在func2 里执行到 count += 100 的时候就会直接到外层函数去寻找这个count 变量。不管你套了多少层函数,python都只会按照就近原则,即最靠近 引用该变量的这个函数的 count ,但只要你声明了nonlocal python就不会去全局名称空间搜索这个 count 变量,如果在外层函数查找不到这个变量就报错。

posted @ 2022-12-04 22:45  种树人  阅读(451)  评论(0编辑  收藏  举报