我想创建现有包的类的子类(我不想/无法更改其源代码)。该类的对象仅使用字符串进行初始化,然后在以后使用所有类型的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)许多要向其中添加功能的实例,这可能会很烦人。
答案 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