最常见的是函数内使用未定义变量:python按legb规则查找,若全局也未定义则报nameerror;需注意global声明、赋值触发局部变量、调用顺序、拼写、导入方式及条件分支覆盖等问题。

变量在函数里用,但没在函数内定义
这是最常见的情况:你在函数里写了 print(x),但 x 只在函数外赋过值。Python 不会自动把全局变量“拉进”函数作用域——它只按 LEGB 规则查找:Local → Enclosing → Global → Built-in。如果函数内部没声明 x,又没在嵌套作用域中定义,就会直接跳到全局;但如果全局也没定义,就报 NameError: name 'x' is not defined。
实操建议:
- 确认
x是否真的在当前执行路径中被赋值(比如写在if分支里,但实际走的是else) - 若需读取并修改全局变量,在函数开头加
global x - 若只是读取,不加
global也能访问全局变量——但一旦你在函数内给x赋值(如x = 5),Python 就默认你是在定义局部变量,此时再读取未初始化的x会触发UnboundLocalError,不是NameError,这点容易混淆
函数调用早于定义,或拼写不一致
Python 是自上而下执行的。如果你写了 greet(),但 def greet(): 在它下面,运行时就会报 NameError: name 'greet' is not defined。同样,my_list 和 my_listt 看似只差一个字母,但就是两个名字。
实操建议:
- 检查调用位置是否在
def或class定义之后(交互式环境或脚本顶部顺序很重要) - 用 IDE 的“跳转到定义”功能验证变量/函数是否真能被解析到
- 对易错名(如
control_queue、config_dict)复制粘贴定义处的完整拼写,避免手误
模块导入失败导致名称不可见
import math 后不能直接用 sqrt(4),必须写 math.sqrt(4);而 from math import sqrt 才允许直接调用 sqrt。如果漏掉 import 或写错模块名(比如把 pathlib 写成 pathlib2),对应名称就根本不在当前命名空间里。
实操建议:
- 运行前先确认导入语句无语法错误,且模块确实已安装(
pip show module_name) - 区分
import xxx和from xxx import yyy对名称可见性的影响 - 注意 Python 3 移除的内置名:比如
reload需要from importlib import reload,unicode应改用str,xrange改用range
条件分支中变量未全覆盖定义
写 if cond: x = 1,然后在 if 外写 print(x),当 cond 为 False 时,x 根本没被创建。Python 不会在运行前“预判”所有分支,它只执行走到的那条路。
实操建议:
- 所有可能用到的变量,尽量在函数入口处统一初始化(如
x = None) - 用静态检查工具(如
pylint)捕获“used before assignment”类警告 - 避免依赖“看起来总会执行”的逻辑——比如以为某个
try/except里的return永远不会发生
真正容易被忽略的是:同一个名字在不同作用域里反复出现,但你以为它“自然延续”,其实 Python 已经把它当作全新局部变量处理了。比如在循环里写 for i in range(3): result = i * 2,接着写 print(result) —— 这看似没问题,但如果循环一次都没执行(空列表),result 就根本不存在。这种隐式依赖执行路径的写法,比显式报错更难排查。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











