2012-03-02 11 views
30

deepcopy da copy non copia una classe:Come copiare una classe python?

>>> class A(object): 
>>>  ARG = 1 

>>> B = deepcopy(A) 

>>> A().ARG 
>>> 1 

>>> B().ARG 
>>> 1 

>>> A.ARG = 2 

>>> B().ARG 
>>> 2 

E 'unico modo?

B(A): 
    pass 
+1

Nota: la domanda corretta sarebbe "Come copiare l'istanza della classe python, o l'oggetto python", non la classe python stessa. –

+20

In realtà, Pavel, sembra che I159 stia effettivamente cercando di copiare la classe stessa –

+1

Senza contare che in Python, una classe è solo un altro oggetto, ma con uno strano attributo '__dict__'. –

risposta

31

In generale, l'eredità è la strada giusta da percorrere, come già sottolineato dagli altri utenti.

Tuttavia, se si vuole veramente di ricreare lo stesso tipo con un nome diverso e senza eredità allora si può fare in questo modo:

class B(object): 
    x = 3 

CopyOfB = type('CopyOfB', B.__bases__, dict(B.__dict__)) 

b = B() 
cob = CopyOfB() 

print b.x # Prints '3' 
print cob.x # Prints '3' 

b.x = 2 
cob.x = 4 

print b.x # Prints '2' 
print cob.x # Prints '4' 

Bisogna stare attenti con i valori degli attributi modificabili:

class C(object): 
    x = [] 

CopyOfC = type('CopyOfC', C.__bases__, dict(C.__dict__)) 

c = C() 
coc = CopyOfC() 

c.x.append(1) 
coc.x.append(2) 

print c.x # Prints '[1, 2]' (!) 
print coc.x # Prints '[1, 2]' (!) 
+0

Il ditt della classe copiata è collegato al dict della classe che è stato creato per primo? – I159

+0

@ I159: Dipende dai valori in '__dict__'. Gli attributi non mutabili vanno bene, ma i valori degli attributi mutabili (come gli elenchi) oi meccanismi di sfondo delle nuove classi di stile (ad esempio descrittori) probabilmente ti morderanno. –

+0

Questo funziona bene solo se all'attributo 'x' è assegnato un tipo immutabile e non un tipo mutabile, perché' dict (C .__ dict __) 'fa solo una copia superficiale, non una copia profonda. – hynekcer

18

Il modo giusto di "copiare" una classe, è, come si supporre, eredità:

class B(A): 
    pass 
+13

Puoi anche farlo usando 'type()', ad es. 'B = type (" B ", (A,), {})' – kindall

+5

L'ereditarietà non fa ciò che è richiesto (inddenza dei valori ARG) a meno che un valore sia assegnato anche a B.ARG. – hynekcer

+0

@hynecker: potresti spiegare cosa intendi con questo? Penso che questo risponda alla domanda dell'OP –

-1

Se si desidera creare solo un altro esempio di classe poi basta lo rendono:

>>> class A(object): 
... ARG=1 
... 
>>> a = A() 
>>> A().ARG 
1 
>>> b = A() 
>>> b.ARG 
1 
>>> a.ARG=2 
>>> b.ARG 
1 
1

Crea il tuo costruttore, e solo duplicare come hai fatto la classe originale:

class MyClass(object): 
    def __init__(self, **kw): 
     self.kw = kw 
     self.__dict__.update(kw) 

    def copy(self): 
     return MyClass(**self.kw) 

Vorrei provare a evitare la necessità di copiare gli oggetti in primo luogo però.


sidenote: Si potrebbe anche essere in grado di ottenere via con fare:

B = deepcopy(A) 
B.__dict__ = deepcopy(A.__dict__) 

ma questo è probabilmente molto molto male e non si dovrebbe fare. edit: in realtà AttributeError: 'dictproxy' object has no attribute 'update' secondo l'OP

+0

In realtà "AttributeError": l'oggetto "dictproxy" non ha alcun attributo "update" – I159

7

Si potrebbe utilizzare una funzione di fabbrica:

def get_A(): 
    class A(object): 
     ARG = 1 
    return A 

A = get_A() 
B = get_A() 
2

Penso che si fraintendono il significato della variabile statica qui. Ogni dove dichiari una variabile al di fuori di un metodo e non nella forma di self.some_thing, la variabile sarà considerata come variabile statica della classe (come la tua variabile ARG qui). Pertanto, ogni oggetto (istanza) della classe che modifica una variabile statica causerà il cambiamento di tutti gli altri oggetti nella stessa classe. La deepcopy fa davvero il lavoro qui.