Python with块中名称作用域疑问:trap为何在块外仍可用?
Python
with块变量作用域疑问解析 问题背景
我正在更新一段Python测试脚本,遇到一处难以理解的代码结构:
with RequestTrap(self.channel) as trap: request = self.task[0].svc.create({'task_use': TaskUse.STANDARD}) request.request_data.attribute_structures.task_use.idnum = attr # Verify the request will return an unexpected attribute in list error. try: trap.response except ResponseError as err: test.eq(err.generalStatus, CipGeneralStatus.UNEXPECTED_ATTRIBUTE_IN_LIST) test.eq(err.extendedStatus, None) else: test.logfail("Class level - Incorrect error response, expecting" "UNEXPECTED_ATTRIBUTE_IN_LIST: attribute=%d" % attr)
我想了解名称“trap”的作用域:它似乎应该仅在with块内定义,但块内并未使用它,且RequestTrap类确实有一个名为request的属性。为何trap在with块外仍能被访问?
解答
在Python中,with语句里as绑定的变量(比如这里的trap),作用域并不局限于with块内部——它遵循Python普通变量的作用域规则,和所在的外层代码块(比如当前函数、方法)保持一致。
具体执行逻辑可以拆解为:
- 先执行
RequestTrap(self.channel)创建上下文管理器实例 - 调用该实例的
__enter__()方法,将返回值赋值给as后的trap变量 - 执行
with块内的代码逻辑 - 块内代码执行完毕后,调用实例的
__exit__()方法完成资源清理,但trap变量并不会被销毁,只要还处于它的作用域范围内(比如当前函数未执行结束),就可以继续访问。
这段代码里trap在with块内没被直接使用,是因为with块内的self.task[0].svc.create(...)操作已经和RequestTrap的上下文完成绑定——RequestTrap的作用应该是拦截捕获该create方法发起的请求,所以后续在块外访问trap.response才能获取到请求对应的响应(或错误信息)。
额外补充:如果RequestTrap的__enter__()方法返回的是实例自身,那trap就是该实例;如果返回的是其他对象,trap则对应那个返回对象,但无论哪种情况,变量的作用域都不受with块的限制。
内容的提问来源于stack exchange,提问作者ROBERT RICHARDSON
相关产品推荐
相关产品推荐

