如何使用父类中的对象最佳地初始化子类的对象?

时间:2018-06-26 13:21:21

标签: python class inheritance

我想创建现有包的类的子类(我不想/无法更改其源代码)。该类的对象仅使用字符串进行初始化,然后在以后使用所有类型的add函数进行填充。一个最小的示例可能看起来像这样(没有任何add函数):

import copy


class Origin(object):
    def __init__(self, name):
        self.name = name
        self.dummy_list = [1, 2, 'a']
        self.dummy_stuff = {'a': [12, 'yt']}

    def make_copy(self):
        return copy.deepcopy(self)

    def dummy_function(self):
        return len(self.dummy_list)

我想创建一个子类,以便可以使用Origin的实例初始化其实例。一种简单的方法是

class BasedOnOrigin(Origin):
    def __init__(self, origin_instance, new_prop):
        Origin.__init__(self, origin_instance.name)
        self.dummy_list = copy.deepcopy(origin_instance.dummy_list)
        self.dummy_stuff = copy.deepcopy(origin_instance.dummy_stuff)
        self.new_prop = new_prop

这里令人烦恼的是,我需要复制所有我需要事先了解的东西。

另一个选择是

class BasedOnOrigin2(Origin):
    def __init__(self, origin_instance, new_prop):
        Origin.__init__(self, origin_instance.name)
        self = origin_instance.make_copy()
        self.new_prop = new_prop

但是self =部分看起来很不标准,并且new_prop未设置,因此我需要一个额外的功能。

是否有执行此操作的标准方法?

上述方法的替代方法是使用以下方法将其他功能添加到现有实例中:

from functools import partial

def add_function(obj, func):

    setattr(obj, func.__name__, partial(func, obj))

但是如果有(i)要添加许多功能并且(ii)许多要向其中添加功能的实例,这可能会很烦人。

2 个答案:

答案 0 :(得分:2)

  

但是self =部分看起来很不标准,并且未设置new_prop

self只是一个简单的局部变量,因此重新绑定它实际上只会影响局部范围。

  

是否有标准的方法?

根据您的描述,这似乎是您的真正问题,是您有一个您不想/无法修改的由另一个lib创建的类的实例,而您真正想要的是添加新方法(并最终覆盖某些方法)这些对象,但是不能,因为您可以告诉此lib使用您自己的类。

如果要点仅是简单地用您自己的版本“替换”原始类(因此原始类的所有实例都会受到更改的影响),则规范的解决方案是monkeypatch the original class

from otherlib import TheClass

def patch_the_class():
    # we do this in a function to avoid
    # polluting the global namespace

    # add a new method

    def newmethod(self):
       # code here

    TheClass.newmethod = newmethod

    # override an existing method

    # keep a reference to the original so
    # we can still use it:
    _original = TheClass.some_method

    def mymethod(self, arg):
        something = _original(self, arg)
        # additional stuff here
        return something

    TheClass.some_method = mymethod

patch_the_class()           

只要确保在执行任何使用补丁的类之前就已经执行了此操作,就可以了。

此解决方案的优点(可以对每个实例分别进行wrt /打补丁)的成本较低,并且可以确保没有人会忘记打补丁。

现在请注意,将猴子补丁视为临时替代方法或最后手段。如果您要修补的库是OSS,则可以对其进行修改以改进原始类,或实施某种方式使具体类使用可配置的并将其贡献回去。

答案 1 :(得分:0)

我认为最好的方法是定义一个函数,该函数将扩展原始origin instance而不复制它,例如

def exdend(*origin_instances):
    def my_function_one(self):
        pass
    def my_function_two(self):
        pass

    for origin_instance in origin_instances:
        setattr(origin_instance, my_function_one.__name__, partial(my_function_one, origin_instance))
        setattr(origin_instance, my_function_two.__name__, partial(my_function_two, origin_instance))

    return origin_instances