我正在使用一些开源的python代码,我需要做一些修改。这是开始的情况。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)
我需要改变
我需要做的什么是两件事:
让
BaseGatherer::get_string()
返回它的my_string
,插入的修改每次调用时都会发生更改。例如,它第一次被调用我得到my_string[0:1] + 'loc=0' + my_string[1:]
,我第二次获得'my_string[0:1] + 'loc=10' + my_string[1:]
等修改
BaseDoer::do_it()
调用BaseDoer::do_stuff()
在一个循环(直到有停止条件),每段时间设定string_needed
与some_gatherer.get_string()
它通过每次调用#1都会返回一个不同的字符串。
有下列限制
- 我使用的基本代码将定期更新,我不希望在所有修改的代码;我希望能够克隆我从中获得的回购,并且只能修改我的“扩展”代码。可以假设
BaseGatherer
和BaseDoer
类的名称在基本代码中没有更改,也没有我在意的方法的名称,尽管我不需要修改的某些辅助方法将得到更新(其中对我来说是关键)。
我的问题
我的主要问题是什么是最好的,最Python化的方式做到这一点?
我尝试
鉴于我所提到的限制,我的第一个倾向是写两个BaseGatherer
和BaseDoer
这使我需要分别编写的get_string()
和do_it()
方法的新版本的变化的派生类。但是,我有一种感觉,我应该使用函数装饰器来做到这一点。我已经阅读了他们一些,我得到了基本的想法(他们包装一个函数,以便您可以控制/修改传递给参数或从你正在包装的函数返回的值,而不修改该函数?;请纠正我,如果我我错过了关键的东西)。但是,我不知道如何在派生类中实现它,无论在语法上还是逻辑上。例如,我是否必须给函数装饰器编写一个@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
方法,而不是基类人的。
但是,有这样的问题,不符合我上面的目标/要求:BaseGatherer::get_string()
和BaseDoer::do_it()
执行很多其他功能,我不得不复制到我的新功能(请参阅其中的评论) 。这意味着当我使用的代码得到更新时,我必须进行复制以更新我的派生类。但是,我只是在改变你在这里看到的内容:在每次调用时都会改变的字符串中插入一些内容,然后在do_it()
的末尾处放置一个循环。这就是为什么我有一种感觉,即函数装饰器是要走的路。我可以包装get_string()
和do_it()
,这样对于前者,我可以通过查看本地计数器来修改每个调用的字符串,对于第二个,我可以只有一个循环,在循环中调用基地do_it()
并传递不同的字符串每次(可以多次拨打do_it()
)。
任何帮助建议最好的方式来做到这一点,以及如何将非常感激。
谢谢!
如果你打算子类,只是子类。不要打扰装饰者。如果你需要将它们应用到多个地方,装饰者是非常棒的,但在这里并不是这样。 –
感谢您的回应,但正如我在最后提到的,我在这里的尝试要求我为基本方法'get_string()'和'do_it()'复制一堆逻辑到我的新版本中(我只是将它遗漏了这里)。我想做的是“重载”基本方法,而不必重写所有的逻辑,因此每次使用我的代码时都更新我的代码。我想跟随DRY。 – ministry
如果您需要复制代码,装饰者不会让您避免复制代码。装饰者不是那样的魔术。 –