Python访问者模式装饰器执行逻辑及内部交互原理问询
关于Python访问者模式装饰器的两个核心疑问
一、为什么decorator(fn)不在调用阶段执行?
Python里的装饰器(包括这种带参数的装饰器)是在函数/类定义阶段就执行完毕的,根本轮不到调用visitor.visit(animal)的时候才跑。
拆解下实际流程:
当你写@visitor(Animal)的时候,Python会先执行visitor(Animal),返回decorator函数;紧接着就把下面的处理函数(比如visit_animal)传给decorator执行——这个过程是脚本加载、类初始化时完成的,目的是把Animal类型和对应的处理函数绑定到visitor的内部映射表(比如一个字典)里。
而调用visitor.visit(animal)时,走的是_visitor_impl的逻辑:直接去之前建好的映射表里找对应类型的处理函数执行。这时候decorator早就完成注册工作了,自然不会再执行。
至于注释decorator里的代码会触发KeyError,原因很直接:跳过了注册步骤,映射表里根本没有Animal对应的处理函数,_visitor_impl找不到就报错了。
二、各函数的交互机制
把几个核心函数的分工和联动逻辑理清楚:
visitor(arg_type):这是参数化装饰器的“入口开关”,接收要处理的目标类型(比如Animal),返回真正的装饰器函数decorator。作用是告诉Python:下面的函数是用来处理arg_type类型实例的。decorator(fn):实际完成注册的函数,接收被装饰的处理函数fn。核心工作是把外层闭包拿到的arg_type和fn绑定,存到visitor类的内部映射结构里(比如self._handlers[arg_type] = fn)。这个步骤在函数定义时完成,为后续调用做准备。_visitor_impl(self, arg):这是visit()方法的实际执行逻辑,调用visitor.visit(animal)本质是调用这个方法。它会先获取arg的类型标识(可能用_qualname或_declaring_class做精准匹配),然后从映射表里找到对应的处理函数,最后调用函数处理arg。_qualname(obj):用来获取对象的限定名称(比如类的完整路径my_module.Animal),比直接用type(arg)更靠谱——能避免不同模块里同名类的冲突,确保映射的key唯一。_declaring_class(obj):一般用来获取实例的实际声明类,或者方法所属的类。比如处理继承场景时,如果子类没有对应的处理函数,它可以帮你找到父类的处理函数,保证访问者模式能正确处理多态情况。
内容的提问来源于stack exchange,提问作者Ken Masters
相关产品推荐
相关产品推荐

