Python使用上下文管理器时as绑定对象为NoneType无法访问属性的原因?
问题原因
出现这个报错的核心逻辑是Python上下文管理器的__enter__方法返回值规则:
with语句中as关键字后绑定的变量,接收的是上下文管理器实例的__enter__方法的返回值,不是上下文管理器实例本身- 你当前写的
__enter__方法没有显式声明返回值,Python会默认给所有无返回值的函数/方法返回None,因此as f实际是把None赋值给了变量f,访问None.name自然会抛出AttributeError
完整执行流程拆解
- 执行
with Foo("dave") as f时,首先会实例化Foo类,调用__init__方法打印INIT,给实例设置name属性,这一步和直接实例化的逻辑完全一致 - 紧接着with语句自动调用这个实例的
__enter__方法,打印ENTER、设置self.age属性,但因为方法没有return语句,最终返回None - 将
__enter__的返回值None赋值给f,所以在with代码块内访问f本质就是访问None
为什么直接实例化可以正常访问?
直接执行f = Foo("dave")时,变量f接收的就是Foo类的实例对象本身,实例已经在__init__中被设置了name属性,所以可以正常访问。
修复方案
如果需要让as绑定的变量指向上下文管理器实例,只需要在__enter__方法末尾显式返回实例本身即可:
class Foo(): def __enter__(self): print("ENTER") self.age = 23 return self # 新增这行返回当前实例 def __exit__(self, exc_type, exc_value, traceback): print("EXIT") def __init__(self, name): print("INIT") self.name = name
修改后再执行with Foo("dave") as f,f就会指向Foo类的实例,访问f.name会正常输出dave。
内容的提问来源于stack exchange,提问作者Precise Profile
相关产品推荐
相关产品推荐

