卡码笔记-最强八股文
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
  • 本栏必读

    • Python面试题专栏介绍
    • Python学习路线
    • Python零基础入门课
  • 基础语法

  • 函数、作用域与模块

    • Python函数参数是值传递还是引用传递?
    • 位置参数、关键字参数、*args和**kwargs怎么用?
    • Python默认参数为什么不能随便使用列表和字典?
    • Python中的匿名函数、map、filter和reduce怎么用?
    • Python的LEGB作用域是什么?
    • global和nonlocal有什么区别?
      • 简要回答
      • 详细回答
      • 知识拓展
    • 什么是闭包?闭包中的变量为什么会出现延迟绑定?
    • Python模块和包是什么?import是怎么工作的?
  • 面向对象

  • 进阶语法与语言机制

# global和nonlocal有什么区别?

面试官问:"global和nonlocal分别用来做什么?什么时候必须用?"

很多人知道"global修改全局变量",但不清楚只读全局变量是否需要声明、nonlocal查找哪一层作用域,以及两者不能混用的原因。

# 简要回答

global声明名字引用全局作用域的变量,让函数内的赋值操作修改模块级全局变量,而不是创建局部变量。

nonlocal声明名字引用外层函数的局部变量,让内层函数可以修改外层函数(Enclosing作用域)的变量。

只读变量不需要声明,只有赋值操作才需要global或nonlocal。global作用于模块全局作用域,nonlocal作用于最近的外层函数作用域,两者不能同时声明同一个名字。

# 详细回答

# 只读全局变量不需要声明

函数内可以直接读取全局变量:

count = 0

def read_count():
    print(count)  # 读取全局变量,不需要global

read_count()  # 0
1
2
3
4
5
6

LEGB规则自动查找到Global作用域的count。

# 修改全局变量需要global

如果函数内对全局变量赋值,必须用global声明:

count = 0

def increment():
    global count
    count = count + 1  # 修改全局变量

increment()
print(count)  # 1
1
2
3
4
5
6
7
8

不声明会报错:

count = 0

def increment():
    count = count + 1  # UnboundLocalError

increment()
1
2
3
4
5
6

因为赋值操作让Python认为count是局部变量,但在赋值前读取count时,局部变量还没有值。

# global的作用范围

global声明后,整个函数内对该名字的赋值都作用于全局作用域:

x = 10

def func():
    global x
    x = 20
    x = x + 5
    print(x)  # 25

func()
print(x)  # 25,全局x被修改
1
2
3
4
5
6
7
8
9
10

# nonlocal修改外层函数变量

嵌套函数可以读取外层函数的局部变量,但修改时需要nonlocal:

def outer():
    count = 0
    
    def inner():
        nonlocal count
        count = count + 1
    
    inner()
    print(count)  # 1

outer()
1
2
3
4
5
6
7
8
9
10
11

不声明会创建局部变量,外层的count不变:

def outer():
    count = 0
    
    def inner():
        count = count + 1  # UnboundLocalError
    
    inner()

outer()
1
2
3
4
5
6
7
8
9

# nonlocal查找最近的外层作用域

nonlocal查找最近的Enclosing作用域,不会跨越到Global:

def outer():
    x = "outer"
    
    def middle():
        x = "middle"
        
        def inner():
            nonlocal x
            x = "inner"
        
        inner()
        print(x)  # inner,修改的是middle的x
    
    middle()
    print(x)  # outer,outer的x未被修改

outer()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

inner中的nonlocal x绑定到middle的局部变量x,不会绑定到outer的x。

global和nonlocal作用对象对比

# nonlocal必须找到外层变量

nonlocal声明的名字必须在外层作用域已经存在,否则报错:

def outer():
    def inner():
        nonlocal count  # SyntaxError: no binding for nonlocal 'count' found
        count = 0
    
    inner()

outer()
1
2
3
4
5
6
7
8

global可以创建全局变量,nonlocal不能创建外层变量。

# global和nonlocal不能同时声明

一个名字不能同时用global和nonlocal声明:

x = 10

def outer():
    x = 20
    
    def inner():
        global x
        nonlocal x  # SyntaxError: name 'x' is nonlocal and global
        x = 30
    
    inner()

outer()
1
2
3
4
5
6
7
8
9
10
11
12
13

必须选择其中一个。

# 闭包中的修改

nonlocal是实现闭包计数器的关键:

def make_counter():
    count = 0
    
    def counter():
        nonlocal count
        count += 1
        return count
    
    return counter

c1 = make_counter()
print(c1())  # 1
print(c1())  # 2

c2 = make_counter()
print(c2())  # 1,独立的计数器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

每个闭包保存独立的count,nonlocal让counter可以修改这个外层变量。

# 知识拓展

Q1:可以用global声明不存在的全局变量吗?

可以。global声明后,函数内的赋值会在全局作用域创建变量:

def create_global():
    global new_var
    new_var = 100

create_global()
print(new_var)  # 100
1
2
3
4
5
6

但这样的代码可读性差,容易引入隐式依赖。

Q2:为什么只读变量不需要声明?

因为LEGB规则自动查找。只有赋值操作会创建新的局部变量,破坏查找链,所以需要显式声明"这个名字不是局部的"。

Q3:可以在一个global语句中声明多个变量吗?

可以:

x, y = 10, 20

def func():
    global x, y
    x = 30
    y = 40

func()
print(x, y)  # 30 40
1
2
3
4
5
6
7
8
9

nonlocal同理。

Q4:在类方法中可以用global修改类属性吗?

不能。global只作用于模块全局作用域,不作用于类命名空间:

class MyClass:
    x = 10
    
    def method(self):
        global x  # 声明模块全局的x,不是类属性
        x = 20

obj = MyClass()
obj.method()
print(MyClass.x)  # 10,类属性未变
print(x)  # 20,创建了模块全局变量
1
2
3
4
5
6
7
8
9
10
11

修改类属性用MyClass.x = 20或self.__class__.x = 20。

Q5:什么时候应该避免用global和nonlocal?

频繁使用global会引入全局状态,降低函数的可测试性和可维护性。更好的做法:

  • 用参数传递需要修改的值。
  • 用类封装状态。
  • 返回新值而不是修改外部变量。

nonlocal在闭包中合理使用,但嵌套层数过多时会降低可读性。

Last Updated: 10/13/2026, 5:57:00 PM

← Python的LEGB作用域是什么? 什么是闭包?闭包中的变量为什么会出现延迟绑定? →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪