使用globals()[]创建Python类实例触发NameError的原因及解决方案
问题原因解析
- 第一个核心问题是变量作用域规则:你写的
myCar = Cars()是在metaObject函数内部定义的,属于函数局部变量,仅在函数运行期间的局部作用域生效,函数执行完成后局部作用域会被回收,外部全局作用域自然找不到myCar这个变量,就会触发NameError。 - 第二个问题是你对
globals()的用法理解有偏差:你执行globals()[attributeList[index]] = myInfoList[index]的时候,attributeList[index]的值是类似'myCar.make'的字符串,这行代码本质是在全局命名空间里新建了一个键名为'myCar.make'的全局变量,而不是给myCar对象新增make属性,两者完全是独立的存储单元。你之前函数内部的打印也只是输出了这个全局变量的值,和myCar对象没有关联。
修正方案
你要实现「函数内部给Cars实例动态加属性,外部可以访问这个实例」的需求,有两种常用改法:
方案1:函数返回实例对象(更符合Python最佳实践)
直接把构造好的myCar实例作为函数返回值抛出,外部接收即可,动态给对象加属性用内置的setattr方法,不需要拼字符串写入全局命名空间:
class Cars: info = ['make', 'model', 'type', 'year'] def metaObject(): myCar = Cars() myInfoList = ['Toyota', 'Prius', 'Sedan', 2010] for attr_name, attr_value in zip(myCar.info, myInfoList): # 给对象动态设置属性用setattr方法 setattr(myCar, attr_name, attr_value) print(f'myCar.{attr_name} = {attr_value}') # 把构造完成的实例返回给外部调用方 return myCar # 外部接收返回的实例 myCar = metaObject() # 可以正常访问属性 print(myCar.make)
方案2:把myCar声明为全局变量(匹配你最初的globals试验逻辑)
如果你要验证全局命名空间的运行机制,可以在函数内部把myCar声明为全局变量,再完成属性赋值:
class Cars: info = ['make', 'model', 'type', 'year'] def metaObject(): # 声明myCar是全局作用域变量 global myCar myCar = Cars() myInfoList = ['Toyota', 'Prius', 'Sedan', 2010] for attr_name, attr_value in zip(myCar.info, myInfoList): setattr(myCar, attr_name, attr_value) # 如果你非要通过globals操作实现属性赋值,写法如下: # globals()['myCar'].__setattr__(attr_name, attr_value) metaObject() # 此时全局作用域已经存在myCar变量,可以正常访问 print(myCar.make)
内容的提问来源于stack exchange,提问作者ZwiTrader
相关产品推荐
相关产品推荐

