代码之家  ›  专栏  ›  技术社区  ›  Cleb

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

  •  2
  • Cleb  · 技术社区  · 6 年前

    我想创建一个现有包类的子类(其源代码我不想/不能更改)。类的对象只使用字符串初始化,然后在以后使用所有类型的 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 回复  |  直到 6 年前
        1
  •  2
  •   bruno desthuilliers    6 年前

    但是self=part看起来很不标准,而且没有设置新的支柱

    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()           
    

    只要确保在使用修补类之前执行此操作,就可以完成。

    这个解决方案的pro(wrt/单独修补每个实例)成本更低,并保证不会有人忘记修补实例。

    现在请注意,monkeypatches将被视为一种临时解决方案或最后手段。如果您要修补的库是oss,您可以对其进行修改,以改进原始类,或者实现某种方法,使具体的类使用可配置的,并将其贡献回来。

        2
  •  0
  •   donnyyy    6 年前

    我认为最好的方法是定义一个函数来扩展原始的 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