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

2024-10-01 15:42:40 发布

您现在位置: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)

在外部,这将被用于如下:

^{pr2}$

需要改变什么

我需要做的是两件事:

  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()(直到某个停止条件),每次用some_gatherer.get_string()设置{},而{}在每次调用中返回不同的字符串。

有以下限制

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

我的问题

我的主要问题是什么是最好的、最具Python式的方法来做到这一点?在

我的尝试

考虑到我提到的限制,我的第一个倾向是编写BaseGatherer和{}的派生类,它们通过分别编写get_string()和{}方法的新版本来进行所需的更改。但是,我觉得应该使用函数修饰符来完成这项工作。我已经读了一点,我得到了基本的想法(他们包装了一个函数,这样你就可以控制/修改传递给你包装的函数的参数或返回的值,而不需要修改这个函数?;如果我遗漏了一些重要的东西,请纠正我)。但是,我不知道如何在派生类中实现它,无论是语法上还是逻辑上。例如,是否必须给我编写@classmethod装饰器的函数decorator?如果是,为什么?在

这是我所做的。它很管用,但我想学习和理解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()和{}都要执行许多其他功能,我必须将这些功能复制到我的新函数中(参见其中的注释)。这意味着当我使用的代码更新时,我必须复制来更新我的派生类。但是,我只是改变了您在这里看到的:在字符串中插入一些随每次调用而变化的内容,并在do_it()的末尾放置一个循环。这就是为什么我有一种感觉,函数装饰器是一种方法。我可以同时包装get_string()do_it(),这样对于前者,我可以通过查看本地计数器来修改每次调用的字符串;对于第二个,我只需要一个循环,在循环中调用基do_it(),并且每次传递一个不同的字符串(多次调用do_it()是可以的)。在

如有任何关于最佳方法和方法的建议,我们将不胜感激。在

谢谢你!在


Tags: 方法函数代码selfgetstringmydef
2条回答

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

使用纯继承最容易做到这一点,无需重复代码:

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)

相关问题 更多 >

    热门问题