Python闭包中如何规范获取外层函数传入的绑定变量
Python获取闭包绑定外层变量的规范方法
完全可以通过Python标准属性获取闭包绑定的外层变量,不需要操作内存的hack手段。
你之前排查时观察到的__closure__属性就是官方提供的访问入口:
- 闭包函数的
__closure__属性会返回一个cell对象组成的元组,每个cell对应一个被闭包捕获的外层自由变量 - 直接读取cell对象的
cell_contents属性,就能拿到该cell存储的实际绑定值,这是Python公开支持的标准访问方式,不存在兼容性问题
针对你给出的html_tag闭包示例,直接按如下方式读取即可:
def html_tag(tag): print(" : <{t}>".format(t=tag)) def wrap_text(msg): print("<{t}>{m}<{t}>".format(t=tag, m=msg)) return wrap_text print_h1 = html_tag("h1") print_div = html_tag("div") print_span = html_tag("span") # 直接读取cell_contents获取绑定的tag值 print(print_h1.__closure__[0].cell_contents) # 输出 h1 print(print_div.__closure__[0].cell_contents) # 输出 div print(print_span.__closure__[0].cell_contents)# 输出 span
你之前直接访问print_h1.tag抛出属性错误的原因很简单:tag是外层函数的局部变量,被闭包捕获后存储在cell结构中,并没有被挂载为内部函数的实例属性,自然无法通过点属性直接访问。
如果闭包捕获了多个外层变量,怕硬编码索引出错,可以配合__code__.co_freevars属性做变量名匹配,这个属性返回的自由变量名称元组,和__closure__的cell元组顺序完全一一对应:
def get_closure_binding(func, var_name): for name, cell in zip(func.__code__.co_freevars, func.__closure__): if name == var_name: return cell.cell_contents raise ValueError(f"该闭包未绑定名为{var_name}的外层变量") # 按变量名取值,不需要记索引 print(get_closure_binding(print_h1, "tag")) # 输出 h1
你之前尝试的ctypes直接读内存的方式非常不可靠:对象内存地址每次进程启动都会随机变化,不同Python版本、不同运行环境下内存布局也可能调整,完全没有可移植性,不要在实际代码中使用。
内容的提问来源于stack exchange,提问作者kris
相关产品推荐
相关产品推荐

