2011-11-05 99 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__()) 
相關問題