2

我想创建现有包的类的子类(我不想/不能更改其源代码)。该类的对象仅使用字符串进行初始化,然后使用各种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) 很多实例想要添加函数,这可能会很烦人。

4

2 回答 2

2

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

self只是一个普通的局部变量,所以重新绑定它只会影响局部范围。

有这样做的标准方法吗?

从您的描述看来,您真正的问题是您拥有由另一个库创建的类的实例,您不希望/无法修改,而您真正想要的是向这些对象添加新方法(并最终覆盖某些方法) ,但不能,因为你可以告诉这个库使用你自己的类。

如果这一点纯粹是用您自己的版本“替换”原始类(因此原始类的所有实例都受到更改的影响),则规范的解决方案是对原始类进行猴子补丁:

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/单独修补每个实例)成本较低,并且可以确保没有人会忘记修补实例。

现在请注意,monkeypatches 将被视为临时解决方法或最后手段的破解。如果您要修补的库是 OSS,您可以对其进行修改以改进原始类或实施某种方式使具体类可配置并回馈给它。

于 2018-06-27T09:27:23.393 回答
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
于 2018-06-26T13:31:06.567 回答