类修改后错误方法的执行

2024-10-01 04:43:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在工厂函数中用修改过的方法创建继承类。奇怪的是,在修改之后,执行了错误的方法。 基类可以是这样的:

class StupidClass:
    def func1(self, param1):
        print("you called StupidClass.func1")
        return param1

    def func2(self, param1):
        print("you called StupidClass.func2")
        return 2*param1

现在,为了修改方法,我编写了这个函数,它返回一个新类,继承输入类,但修改函数:

from inspect import signature
from functools import update_wrapper
import copy

def modify(cls):
    """
    Modifies the methods of the passed class and returns a new class
    """
    class ModifiedClass(cls):
        pass

    for attribute_name in dir(cls): # Loop over all attributes 
        if "func" in attribute_name: # Select all attributes that have "func" in their name
            attribute = getattr(cls, attribute_name)

            print("modifying method", attribute)
            def temp_meth(inst, param1):
                print("you called ModifiedClass." + attribute_name)
                return attribute(inst, param1)

            setattr(ModifiedClass, attribute_name, temp_meth)
    return ModifiedClass

当我跑的时候

inst = StupidClass()
inst.func1(1)
inst.func2(1)

我得到了预期的输出:

you called StupidClass.func1
1
you called StupidClass.func2
2

但是当我在修改后的类中执行方法时,它总是调用func2:

ModCls = modify(StupidClass)
mod_inst = ModCls()

mod_inst.func1(1)
mod_inst.func2(1)

输出:

modifying method <function StupidClass.func1 at 0x7fa4c802e6a8>
modifying method <function StupidClass.func2 at 0x7fa4c802e730>
you called ModifiedClass.func2
you called StupidClass.func2
2
you called ModifiedClass.func2
you called StupidClass.func2
2

解决方案 与其他编程语言不同,Python不创建for循环的作用域,因此出现了这个问题。要解决这个问题,只需围绕代码创建一个函数:

from inspect import signature
from functools import update_wrapper
import copy

def modify(cls):
    """
    Modifies the methods of the passed class and returns a new class
    """
    class ModifiedClass(cls):
        pass

    for attribute_name in dir(cls): # Loop over all attributes 
        if "func" in attribute_name: # Select all attributes that have "func" in their name
            attribute = getattr(cls, attribute_name)
            def just_to_add_a_scope(ModifiedClass, attribute_name, attribute):
                print("modifying method", attribute)
                def temp_meth(inst, param1):
                    print("you called ModifiedClass." + attribute_name)
                    return attribute(inst, param1)

                setattr(ModifiedClass, attribute_name, temp_meth)
            just_to_add_a_scope(ModifiedClass, attribute_name, attribute)
    return ModifiedClass

Tags: nameyoureturndefattributeclassclsparam1