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

时间:2015-09-19 21:46:07

标签: python python-decorators

我正在使用一些开源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()返回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_needed some_gatherer.get_string(),#1返回不同每个电话都有一个字符串。

  3. 具有以下限制

    • 我正在使用的基本代码定期更新,我根本不想修改该代码;我希望能够克隆我从中获取它的repo,并且可能只需要修改我的“扩展”代码。可以假设BaseGathererBaseDoer类的名称在基本代码中没有变化,我在这里关注的方法的名称也没有,尽管我没有一些辅助方法需要修改才会更新(这对我来说很关键)。

    我的问题

    我的主要问题是 什么是最好,最恐怖的方式

    我的尝试

    鉴于我提到的限制,我的第一个倾向是编写BaseGathererBaseDoer的派生类,通过编写get_string()和{{的新版本来进行我需要的更改1}}方法分别。但是,我有一种感觉,我应该使用函数装饰器来做到这一点。我已经阅读了一些它们,我得到了基本的想法(它们包装了一个函数,以便您可以控制/修改传递给的参数或从您正在包装的函数返回的值而不修改该函数?;如果我,请纠正我我错过了一些重要的事情。但是,我不知道如何在派生类中实现它,无论是语法还是逻辑。例如,我是否必须给函数装饰器写一个do_it()装饰器?如果是这样,为什么?

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

    @classmethod

    然后我会像上面那样调用它,但是创建派生实例并调用它们的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) 方法而不是基类1。

    但是,有些问题不能满足我上面的目标/要求:XLBaseGatherer::get_string()执行许多其他功能,我只需要复制到我的新功能中(见其中的评论)。这意味着当我使用的代码得到更新时,我必须进行复制以更新我的派生类。但是,我只会改变你在这里看到的内容:在每个调用中更改的字符串中插入一些内容,并在BaseDoer::do_it()的末尾添加一个循环。这就是为什么我觉得功能装饰器是要走的路。我可以包装do_it()get_string(),以便对于前者我可以通过查看本地计数器来修改每个调用的字符串,对于第二个我可以只有一个调用基类的循环{ {1}}在一个循环中,每次传递一个不同的字符串(可以多次调用do_it())。

    任何有关如何做到这一点的最佳方式的建议的帮助以及如何非常感激。

    谢谢!

2 个答案:

答案 0 :(得分:1)

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

>>> 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'

答案 1 :(得分:1)

使用普通继承,不重复代码最容易做到这一点:

netstat -u