如何解决Python装饰器中的循环引用问题
解决类装饰器循环引用导致的NameError问题
方法1:使用字符串类名延迟解析
将装饰器参数替换为类的字符串名称,在装饰器内部延迟获取类对象,避免因定义顺序导致的未引用错误。
def foo(bar_name): def decorator_foo(cls): # 此时关联类已完成定义,可通过全局命名空间获取 cls._related_class = globals()[bar_name] return cls return decorator_foo @foo(bar_name='B') class A: pass @foo(bar_name='A') class B: pass # 验证关联关系 print(A._related_class is B) # 输出 True print(B._related_class is A) # 输出 True
方法2:先定义类,后手动设置关联元数据
放弃装饰器即时传递参数的方式,先完成所有类的定义,再通过函数手动添加关联元数据,彻底避开顺序依赖问题。
def set_related_class(cls, related_cls): cls._related_class = related_cls # 先定义所有类 class A: pass class B: pass # 手动绑定关联 set_related_class(A, B) set_related_class(B, A) print(A._related_class is B) # 输出 True print(B._related_class is A) # 输出 True
方法3:用可调用对象延迟获取类
使用lambda或自定义可调用对象作为装饰器参数,让类的引用在装饰器实际执行时才被解析,此时依赖类已完成定义。
def foo(bar_getter): def decorator_foo(cls): # 调用可调用对象获取关联类 cls._related_class = bar_getter() return cls return decorator_foo @foo(bar_getter=lambda: B) class A: pass @foo(bar_getter=lambda: A) class B: pass print(A._related_class is B) # 输出 True print(B._related_class is A) # 输出 True
内容的提问来源于stack exchange,提问作者Sean Butcher
相关产品推荐
相关产品推荐

