3、名称错误(NameError):变量未定义、函数名拼写错误、作用域问题
名称错误,说白了就是 Python 找不到你写的那个名字。
你明明觉得变量已经定义好了,函数名也写对了,可解释器就是一脸茫然地抛出一个 NameError。我刚开始学建模时,几乎每天都要跟它打交道。后来发现,这类错误其实就三种情况:变量没定义、名字写错了、作用域搞混了。
3.1 变量未定义:最常见的翻车现场
先看一个典型例子:
# 错误示例
print(result) # NameError: name 'result' is not defined
result = 42
为什么会这样?因为 Python 执行代码是顺序的。你还没给 result 赋值,就想打印它,它当然不认识。
我在项目中遇到过更隐蔽的情况:
# 条件分支里漏了定义
def process_data(value):
if value > 0:
result = value * 2
# 如果 value <= 0,result 根本没被创建
return result # 可能报 NameError
嗯,这里要注意:条件分支、循环体、异常处理块里定义的变量,如果执行路径没走到,变量就不存在。
result = None。这样不管走哪条路,变量都活着。
3.2 函数名拼写错误:眼睛看花了
这种错误最气人。你盯着代码看了十分钟,愣是没发现哪里写错了。
# 定义时叫 calculate_average
def calculate_average(data):
return sum(data) / len(data)
# 调用时写成了 calculate_avrage
avg = calculate_avrage(scores) # NameError
我个人习惯用 IDE 的自动补全功能。打几个字母,让工具帮你补全函数名,基本能杜绝这种低级错误。
还有一种情况是大小写问题:
def LoadModel(path):
# 加载模型
pass
# 调用时写成了小写
load_model("model.obj") # NameError
Python 是大小写敏感的。LoadModel 和 load_model 是两个完全不同的名字。
3.3 作用域问题:变量藏起来了
作用域,说白了就是变量的可见范围。你在函数里定义的变量,外面看不到;外面定义的变量,函数里可以读,但不能直接改。
看这个例子:
total = 0
def add_to_total(value):
total = total + value # UnboundLocalError
return total
你可能会想:「total 不是全局变量吗?为什么报错?」
因为 Python 在函数内部给 total 赋值时,会把它当成局部变量。而局部变量 total 还没定义,你就想用它,自然报错。
正确的做法是:
total = 0
def add_to_total(value):
global total
total = total + value
return total
或者更推荐的做法——用参数传递:
def add_to_total(total, value):
return total + value
3.4 知识体系:名称错误全景图
下面这张图帮你理清 NameError 的三种根源和对应的解决思路:
3.5 避坑指南:我踩过的那些坑
| 错误类型 | 典型表现 | 排查方法 |
|---|---|---|
| 变量未定义 | NameError: name 'xxx' is not defined |
检查变量是否在之前被赋值,注意条件分支路径 |
| 函数名拼写错误 | NameError: name 'xxx' is not defined |
对比定义处的函数名,检查大小写和下划线 |
| 作用域问题 | UnboundLocalError 或 NameError |
确认变量是在局部还是全局,用 global 或参数传递 |
| 模块导入问题 | NameError: name 'xxx' is not defined |
检查 import 语句是否写对,模块是否已安装 |
create_joint,但 Maya 自带的命令叫 cmds.joint。我写脚本时用了 create_joint 作为变量名,结果跟函数名冲突了。排查了半天才发现,原来是自己不小心把函数名当变量用了。
3.6 快速自查清单
遇到 NameError 时,按这个顺序检查:
- 拼写检查:名字里的每个字母、下划线、大小写都对吗?
- 定义顺序:变量在使用之前定义了吗?
- 执行路径:条件分支、循环、异常处理里有没有漏定义的路径?
- 作用域:变量是在当前作用域里定义的吗?函数内外搞混了没?
- 导入检查:如果是外部模块的函数,import 写了吗?模块名对吗?
嗯,其实 NameError 并不可怕。你想想看,它只是告诉你「这个名字我不认识」。你把它当成一个善意的提醒就好——帮你找到代码里的小漏洞。我个人觉得,能快速定位 NameError,是建模脚本入门的第一道坎。跨过去,后面的路就好走了。