Python - 如何正确扩展类修改基类方法的操作

Python - how to properly extend classes to modify the operation of base methods

我正在使用一些开源 python 代码,我需要对其稍作修改。这是开始的情况。

初始情况

class BaseGatherer:

    def get_string(self):
        #a bunch of stuff I don't need to modify
        return self.my_string #set with a hard value in __init__()

class BaseDoer:

    def do_it(self, some_gatherer):
        #a bunch of stuff I don't need to modify
        string_needed = some_gatherer.get_string()
        self.do_stuff(string_needed)

在外部,这将按如下方式使用:

my_gatherer = BaseGatherer()
my_doer = BaseDoer()
my_doer.do_it(my_gatherer)

我需要改变什么

我需要做的是两件事:

  1. BaseGatherer::get_string() return 它是 my_string 插入的修改,每次调用时都会更改。例如,第一次调用它时我得到 my_string[0:1] + 'loc=0' + my_string[1:],第二次我得到 'my_string[0:1] + 'loc=10' + my_string[1:],等等

  2. 修改BaseDoer::do_it()循环调用BaseDoer::do_stuff()(直到某个停止条件),每次设置string_neededsome_gatherer.get_string(),由# 1 return每次调用都有不同的字符串。

具有以下限制

我的问题

我的主要问题是 最好的、最 Pythonic 的方法是什么

我的尝试

鉴于我提到的限制,我的第一个倾向是编写 BaseGathererBaseDoer 的派生 classes,通过编写 BaseDoer 的新版本来进行我需要的更改=27=] 和 do_it() 方法。但是,我觉得我应该使用函数装饰器来做到这一点。我读了一些关于它们的内容,我得到了基本的想法(它们包装了一个函数,这样你就可以 control/modify 传递给你正在包装的函数的参数或从你正在包装的函数中编辑值 return 而无需修改该函数?;如果我遗漏了一些重要的东西,请纠正我)。但是,我不知道如何在派生的 class 中实现它,无论是语法上还是逻辑上。比如我写的函数装饰器是不是一定要给一个@classmethod装饰器?如果是,为什么?

这是我所做的。它有效,但我想学习和理解 a) 做我想做的事情的正确方法是什么以及 b) 如何实际去做。

class DerivedGatherer(BaseGatherer):

    def __init__(self):
        super(DerivedGatherer, self).__init__() #I'm in Python 2.7 :(
        self.counter = 0 #new variable not in BaseGatherer

    #DON'T override BaseGatherer::get_string(), just write a new function
    def get_string_XL(self):
        self.counter += 10
        return self.my_string[0:1] + 'loc=' + str(self.counter) + self.my_string[1:]

class DerivedDoer(BaseDoer):

    def do_it_XL(self, some_derived_gatherer):
        while(~some_stop_condition()):
            string_needed = some_derived_gatherer.get_string_XL()
            self.do_stuff(string_needed)

然后我会像上面那样调用它,但创建派生实例并调用它们的 XL 方法而不是基本的 class 方法。

但是,这有一些问题不能满足我上面的 goal/requirement:BaseGatherer::get_string()BaseDoer::do_it() 都执行许多其他功能,我必须复制这些功能进入我的新功能(请参阅其中的评论)。这意味着当我使用的代码更新时,我必须进行复制以更新派生的 classes。但是,我只是在更改您在这里看到的内容:在每次调用时更改的字符串中插入一些内容,并在 do_it() 的末尾 放置一个循环 。这就是为什么我觉得函数装饰器是正确的选择。我可以包装 get_string()do_it() 以便对于前者我可以通过查看本地计数器在每次调用时修改字符串,对于第二个我可以只使用一个循环来调用基础 do_it() 在一个循环中,每次传递一个不同的字符串(多次调用 do_it() 是可以的)。

如果您能提供有关最佳方法和方法的建议,我们将不胜感激。

谢谢!

正如 Martijn 向您解释的那样,您可以轻松地从子class 中的方法调用基class 中的方法。你可以用 super 来确保你得到他展示的整个 class 结构。不过,为了举例说明,如果您有一个只有一个超级 class 和一个子 class 的简单层次结构,您可以这样做:

>>> class Foo(object):
...     def xxx(self):
...         return "Foo.xxx was called"
... 
>>> class Bar(Foo):
...     def xxx(self):
...         return "Bar.xxx was called and then %s" % Foo.xxx(self)
... 
>>> Bar().xxx()
'Bar.xxx was called and then Foo.xxx was called'

这最容易通过简单的继承来完成,无需重复代码:

class DerivedGatherer(BaseGatherer):

    def __init__(self):
        super(DerivedGatherer, self).__init__()
        self.counter = 0

    def get_string(self):
        self.counter += 10
        super_string = super(DerivedGatherer, self).get_string()
        return super_string[0:1] + 'loc=' + str(self.counter) + super_string[1:]

class DerivedDoer(BaseDoer):

    def do_it(self, some_derived_gatherer):
        while(~some_stop_condition()):
            super(DerivedDoer, self).do_it(some_derived_gatherer)