如何从Python动态生成的方法中访问self与方法名?
动态生成类方法的问题
我有一个类A,其中多个方法可以通过动态生成来减少样板代码:
class A: def save_foo(self, **kwargs): do_foo_stuff_here() def save_bar(self, **kwargs): do_bar_stuff_here() def save_foobar(self, **kwargs): do_foobar_stuff_here()
尝试动态生成方法后,代码如下:
class A(): pass def _method_generator(cls, **kwargs): if method_name == "save_foo": do_foo_stuff_here() elif method_name == "save_foo": do_bar_stuff_here() elif method_name == "save_foobar": do_foobar_stuff_here() for method_name in ["save_foo", "save_bar", "save_foobar"]: setattr(A, method_name, classmethod(_method_generator))
现在面临两个问题:
- 在
_method_generator中能通过cls访问类,但无法访问实例self,该如何解决? - 需要知道调用的是哪个方法以复现原有逻辑,但现有方法只能获取到
_method_generator,而非实际调用的方法名,该如何处理?
问题1:访问实例self的解决方案
你当前用了classmethod装饰器,所以方法第一个参数是类cls,而非实例self。如果要访问实例,应该直接绑定实例方法(不用classmethod包装),让生成的方法第一个参数接收self。
问题2:获取实际调用方法名的解决方案
可以利用闭包特性,在循环中为每个方法名生成一个绑定了当前名称的函数,这样每个动态生成的方法都能明确知道自己对应的调用名称。
完整修正代码(实例方法场景)
class A(): pass def _method_generator_factory(method_name): # 闭包绑定当前循环的method_name def method(self, **kwargs): # 这里可以直接访问实例self if method_name == "save_foo": print(f"调用save_foo,实例对象:{self}") # do_foo_stuff_here() elif method_name == "save_bar": print(f"调用save_bar,实例对象:{self}") # do_bar_stuff_here() elif method_name == "save_foobar": print(f"调用save_foobar,实例对象:{self}") # do_foobar_stuff_here() return method for method_name in ["save_foo", "save_bar", "save_foobar"]: # 直接绑定实例方法,无需classmethod setattr(A, method_name, _method_generator_factory(method_name)) # 测试调用 a = A() a.save_foo() a.save_bar()
代码说明
_method_generator_factory作为工厂函数,每次循环传入当前method_name,返回一个绑定了该名称的实例方法。- 生成的方法第一个参数是
self,可以直接访问实例的属性和方法。 - 每个动态方法通过闭包持有专属的
method_name,完美复现原有分支逻辑。
类方法场景的适配方案
如果确实需要类方法(无需实例即可调用),只需调整闭包逻辑,保留cls参数:
class A(): pass def _classmethod_generator_factory(method_name): def method(cls, **kwargs): if method_name == "save_foo": print(f"调用类方法save_foo,类:{cls}") # do_foo_stuff_here() elif method_name == "save_bar": print(f"调用类方法save_bar,类:{cls}") # do_bar_stuff_here() elif method_name == "save_foobar": print(f"调用类方法save_foobar,类:{cls}") # do_foobar_stuff_here() return classmethod(method) for method_name in ["save_foo", "save_bar", "save_foobar"]: setattr(A, method_name, _classmethod_generator_factory(method_name)) # 测试类方法调用 A.save_foo()
内容的提问来源于stack exchange,提问作者DobbyTheElf
相关产品推荐
相关产品推荐

