2011-11-05 93 views
3

这很难解释。我有一门课应该支持方法copy_stateonly()。它应该返回一个残缺版本的对象,它只包含我想要的(复制的)数据成员。我希望这个例子更好解释的那样:动态创建类型为(self)的实例而不调用__init__?

# everything inherits from this 
class SuperBase: 
    def __init__(self): 
     self.state_var = 3 # this should be copied into future objects 
     self.non_state_var = 0 # we don't want to copy this 

    def copy_stateonly(self): 
     newobj = # ??????????? create instance without calling __init__ 
     newobj.state_var = self.state_var 
     return newobj 

# some clases inherit from this 
class Base(SuperBase): 
    def __init__(self): 
     SuperBase.__init__(self) 
     self.isflying = True # we want to copy this, this is state 
     self.sprite = "sprites/plane_generic.png" # we must drop this 

    def copy_stateonly(self): 
     newobj = SuperBase.copy_stateonly(self) 
     newobj.isflying = self.isflying 
     return newobj 

class A144fighter(Base): 
    def __init__(self, teamname): # note required __init__ argument 
     Base.__init__(self) 
     self.colors = ["black", "grey"] # we want to copy this, this is state 
     self.name = teamname # we must drop this 

    def copy_stateonly(self): 
     newobj = Base.copy_stateonly(self) 
     newobj.colors = self.colors[:] 
     return newobj 

plane = A144fighter("team_blue") 
plane_state = plane.copy_stateonly() # this should return an A144fighter object with only state_var, flying and colors set. 

的Python 2.7

回答

5

我不知道的一种方式,而无需调用__init__()创建(这是你在你的例子使用了什么)经典类的新实例。新式的类(的object后代)的新实例可以使用

object.__new__(cls) 

其中cls是你想创建对象的类型来创建。

另一种方法是使用copy.copy()进行复制,可能会覆盖__getstate__()__setstate__()以定义应该复制的内容。

编辑:不必呼叫__init__()创造经典类cls的新实例,您可以使用下面的技巧:

class EmptyClass: 
    pass 

new_instance = EmptyClass() 
new_instance.__class__ = cls 
new_instance.__dict__.update(whatever) 
+1

无需破解:'进口类型; types.InstanceType(cls)'(或'import new; new.instance(cls)') –

+2

第二种方法只适用于两个类具有相同布局的情况,这对大多数类来说都是正确的,但不会是,例如,每个班级使用'__slots__'。 – SingleNegationElimination

+0

@TokenMacGuy:正如我所说的,第二种方法只适用于* classic *类。在这种情况下'__slots__'没有意义。 –

0

请记住,每个对象都有一个名为__class__属性。如果你做<object>.__class__它,将返回该对象的类对象(如果这是有道理的)。类对象是可调用的,因此您可以将括号添加到最后以创建该类的新实例。

newobj = self.__class__() 
+0

这仍然会调用'self .__ class __.__ init__' - 可能需要参数,如示例中所示 - 导致错误。 – orlp

+0

啊,我以为你只是不想直接打电话给我。现在,我不会推荐这样做,但是可以解决这个问题的一种方法是使所有参数为可选参数(相信我)并添加另一个可选参数,该参数为布尔值。它应该默认为True。如果你不想要求“required”参数,你可以将它设置为False。如果设置为true,检查是否设置了所有“必需”变量(即它们是否设置为None或其他?)。再次,我不会推荐这个。 –

2
# everything inherits from this 
class SuperBase: 
    def __init__(self): 
     self.state_var = 3 # this should be copied into future objects 
     self.non_state_var = 0 # we don't want to copy this 

    def __getstate__(self): 
     return { 'state_var' : self.state_var } 

    def __str__(self): 
     return self.__class__.__name__ + '(' + str(vars(self)) + ')' 

# some clases inherit from this 
class Base(SuperBase): 
    def __init__(self): 
     SuperBase.__init__(self) 
     self.isflying = True # we want to copy this, this is state 
     self.sprite = "sprites/plane_generic.png" # we must drop this 

    def __getstate__(self): 
     state = SuperBase.__getstate__(self) 
     state['isflying'] = self.isflying 
     return state 

class A144fighter(Base): 
    def __init__(self, teamname): # note required __init__ argument 
     Base.__init__(self) 
     self.colors = ["black", "grey"] # we want to copy this, this is state 
     self.name = teamname # we must drop this 

    def __getstate__(self): 
     state = Base.__getstate__(self) 
     state['colors'] = self.colors[:] 
     return state 

plane = A144fighter("team_blue") 
print plane 

import copy 
print copy.copy(plane) 

# or manually: 
import types 
print types.InstanceType(plane.__class__, plane.__getstate__()) 
相关问题