2012-07-23 60 views
2

我试图避免在两个类的克隆方法中重复相同的代码,一个从另一个继承。我目前的做法是将两个类通用的代码放在基类的(非静态)克隆方法中,并从扩展类中调用它。为此,我试图将扩展类的构造函数传递给基类,以便可以在那里调用它。下面是我目前在做什么一个简单的例子:如何将构造函数方法传递给另一个方法并在那里调用它?

class S(object): 
    """Base class""" 
    def __init__(self): 
     self.a = 0 

    def clone(self, constructor=None): 
     if constructor is None: 
      constructor = self.__init__ 
     cloned = constructor() 
     # Expecting: cloned.a = 1, cloned.b = 7 

     assert cloned is not None # raises AssertionError 
     cloned.a = self.a # Set a to 2 
     return cloned 

class C(S): 
    """Child class, extending Base""" 
    def __init__(self): 
     self.a = 1 
     self.b = 7 

    def clone(self): 
     cloned = super(C, self).clone(self.__init__) 
     # Expecting: cloned.a = 2, cloned.b = 7 

     cloned.b = self.b # Set b to 8 
     return cloned 

if __name__ == '__main__': 
    c1 = C() 
    c1.a = 2 
    c1.a = 8 
    c2 = c1.clone() 

我在这一点上的问题是:

  • 为什么None调用基类的clone方法时返回?

  • 为了使用它,我必须将该方法绑定到类上吗?使用 types.MethodType__get__

  • 作为更好的方法,你会有什么建议?

+0

你知道'copy'模块吗? – 2012-07-23 14:12:36

+0

@KarlKnechtel:是的,但是我做出了一些错误的假设,这让我相信它不足以满足我想要做的事情。事实证明,这是。 – EriF89 2012-07-24 07:40:09

回答

5

虽然__init__()经常被称为Python中的构造函数,但它实际上并不是。它获取作为self参数传入的实例,并返回None。该实例由__new__()方法构建,它是实际的构造函数。不过,您不应传递对__new__的引用。传入类型本身更容易也更直接。

编辑:正确的方法来实现clone方法是另一种:坚持以普通的Python协议,并实现你的情况__getstate__()__setstate__()。然后,您可以使用copy模块中的函数正确地克隆您的实例。

+0

在其他语言中,构造函数也在已分配的内存和构造的上下文中运行,但未初始化对象。 '__init__'究竟有什么不同,它不是构造函数? O_o – BartoszKP 2018-02-07 14:56:34

+0

@BartoszKP这个问题的OP期望构造函数生成一个新的对象并返回它,它不这样做,我回答说明了这一点。也就是说,'__init __()'和一个构造函数在C++中的作用肯定存在差异。最重要的区别是'__new __()'已经返回一个完全工作的对象,在某种情况下甚至是一个初始化的对象(例如对于不可变类型)。 '__new __()'比C++中的分配器要多得多,这就是为什么我在这里称它为“实际”构造函数的原因。 – 2018-02-08 13:00:49

+0

“完全工作”是什么意思?对象是否“完全工作”取决于'__init__'和基类中的代码,它可以执行与C++中的vtables(您可能想到的)完全相同的设置类型。例如,它期望从子类中明确调用base的__init__,所以在这种情况下,我不会称其为“全功能”。 – BartoszKP 2018-02-08 13:42:38

2

您的基类克隆方法是多余的。从任何上下文调用self.__init__()将遵循来自该对象的特定实例的MRO,这意味着在C的实例上调用clone()将从S中的代码调用C.__init__(),而不明确指定使用c.__init__()

如果你想要做的事情虽然可以自定义clone()而不必创建一个全新的类,或者根据其他因素有不同的行为,我建议看看工厂/构建器模式。

此外,专门为clone()类型的操作,你可能想看看超载__copy__()__getstate__(),并__setstate__()copy.copy()copy.deepcopy()工作,而不是实施新的辩证的元素。

相关问题