在不继承的情况下重写类方法(python)

6 投票
5 回答
6992 浏览
提问于 2025-04-16 20:49

首先,如果你们觉得我现在的做法不够“Pythonic”(即不够符合Python的风格),欢迎提出其他建议。

我有一个对象,它的功能需要根据外部事件来改变。我最开始的做法是创建一个新的对象,这个新对象继承自原来的对象(我们称它为OrigObject()),并重写需要改变的方法(我们称这个新对象为NewObject())。然后我修改了两个构造函数,使它们可以接收另一个类型的完整对象,以便根据传入的对象填充自己的值。这样,当我需要改变功能时,我只需执行myObject = NewObject(myObject)

不过,我现在开始发现这种做法有几个问题。首先,其他地方引用这个对象的地方也需要更新,以便引用新的类型(比如上面的语句只会更新本地的myObject变量)。虽然更新这些地方并不难,但每次我改变对象时都要记得更新,避免程序出现奇怪的行为,这确实有点烦。

其次,我发现有些情况我只需要NewObject()中的一个方法,而其他方法还是希望用OrigObject()中的。这时我需要能够随时切换功能。使用继承的方式似乎不太合适,因为我可能需要创建M*N个不同的类(M是类中可以改变的方法数量,N是每个方法的变化数量),这些类都要继承自OrigObject()

我在考虑使用属性重映射,但似乎遇到了一些问题。比如,我有这样的代码:

def hybrid_type2(someobj, a):
    #do something else
    ...

class OrigObject(object):
    ...
    def hybrid_fun(self, a):
        #do something
        ...

    def switch(type):
        if type == 1:
            self.hybrid_fun = OrigObject.hybrid_fun
        else:
            self.fybrid_fun = hybrid_type2

问题是,在这样做之后,当我尝试调用新的hybrid_fun时,出现了一个错误,提示hybrid_type2()需要两个参数,但我只传了一个。这个对象似乎没有像调用自己方法时那样将自身作为参数传递给新函数,有什么办法可以解决这个问题吗?

我尝试把hybrid_type2也放在类里面,然后用self.hybrid_fun = self.hybrid_type2这样做是有效的,但用self.hybrid_fun = OrigObject.hybrid_fun就会出现类似的错误(抱怨第一个参数应该是OrigObject类型)。我知道我可以在OrigObject.hybrid_type1()中定义OrigObject.hybrid_fun()的逻辑,这样我就可以像设置它一样恢复它(相对于实例,而不是相对于类,以避免对象不是第一个参数)。但我想问问这里有没有更简洁的方法?谢谢

编辑:谢谢大家,我给了几个有效解决方案的积分。我最终使用了策略模式和types.MethodType(),我接受了一个解释如何在Python中实现策略模式的答案(维基百科的文章更为一般,而在Python中不需要使用接口)。

5 个回答

2

了解一下Python中的描述符。下面的代码应该可以正常运行:

else:
    self.fybrid_fun = hybrid_type2.__get__(self, OrigObject)
6

你想要的是策略模式

5

使用types模块可以为某个特定的实例创建一个实例方法。

比如:

import types

def strategyA(possible_self):
    pass

instance = OrigObject()

instance.strategy = types.MethodType(strategyA, instance)

instance.strategy()

请注意,这只会影响这个特定的实例,其他实例不会受到影响。

撰写回答