Python:即时重命名方法名称

Uri*_*hen 6 python dynamic decorator

我有许多文件使用以下语法的类:

o = module.CreateObject()
a = o.get_Field
Run Code Online (Sandbox Code Playgroud)

现在实现已从“ get_XXX”和“ set_XXX”更改为“ XXX”:

o = module.CreateObject()
a = o.Field
Run Code Online (Sandbox Code Playgroud)

此实现是一个外部程序包,我不想更改。是否可以编写一个包装程序,该包装程序将即时拦截所有对“ get_XXX”的调用,然后替换为对新名称“ XXX”的调用?

o = MyRenamer(module.CreateObject())
a = o.get_Field   # works as before, o.Field is called
a = o.DoIt()      # works as before, o.DoIt is called
Run Code Online (Sandbox Code Playgroud)

它需要拦截所有调用,而不仅仅是拦截有限的字段,根据方法名称决定是否修改它,并导致调用具有修改名称的方法。

Blc*_*ght 5

如果您想继续在已切换为使用属性的对象上使用get_Fieldand (您只需访问或分配给),可以使用包装对象:set_FieldField

class NoPropertyAdaptor(object):
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, name):
        if name.startswith("get_"):
            return lambda: getattr(self.obj, name[4:])
        elif name.startswith("set_"):
            return lambda value: setattr(self.obj, name[4:], value)
        else:
            return getattr(self.obj, name)
Run Code Online (Sandbox Code Playgroud)

如果您使用额外的语法(例如对象上的索引或迭代),或者需要使用isinstance.

更复杂的解决方案是创建一个子类来进行名称重写并强制对象使用它。这并不完全是包装,因为外部代码仍然会直接处理对象(因此魔术方法 和isinstance)将按预期工作。这种方法适用于大多数对象,但对于具有奇特元类魔法的类型和某些内置类型可能会失败:

def no_property_adaptor(obj):
    class wrapper(obj.__class__):
        def __getattr__(self, name):
            if name.startswith("get_"):
                return lambda: getattr(self, name[4:])
            elif name.startswith("set_"):
                return lambda value: setattr(self, name[4:], value)
            else:
                return super(wrapper, self).__getattr__(name)

    obj.__class__ = wrapper
    return obj
Run Code Online (Sandbox Code Playgroud)