2012-03-02 16 views
30

deepcopy z copy nie kopiuje klasę:Jak skopiować klasę python?

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

>>> B = deepcopy(A) 

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

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

>>> A.ARG = 2 

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

Czy to jedyny sposób?

B(A): 
    pass 
+1

Uwaga: poprawne pytanie brzmi: "Jak skopiować instancję klasy Pythona lub obiekt Pythona", a nie samą klasę Pythona. –

+20

W rzeczywistości, Pavel, wygląda na to, że I159 rzeczywiście chce skopiować klasę. –

+1

Nie wspominając już o tym, że w Pythonie klasa jest po prostu kolejnym obiektem, ale z dziwnym atrybutem '__dict__'. –

Odpowiedz

31

Ogólnie rzecz biorąc, dziedziczenie to właściwa droga, jak wskazały inne plakaty.

Jednakże, jeśli naprawdę chcesz, aby odtworzyć ten sam typ z inną nazwą i bez dziedziczenia następnie można zrobić to tak:

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' 

Trzeba być ostrożnym z modyfikowalnych wartości atrybutu:

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

Czy dict skopiowanej klasy jest powiązany z dict klasy, która została stworzona jako pierwsza? – I159

+0

@ I159: To zależy od wartości w '__dict__'. Atrybuty nieprzemienne są w porządku, ale zmienne wartości atrybutów (takie jak listy) lub mechanizmy tła nowych klas stylów (np. Deskryptorów) prawdopodobnie Cię ugryzą. –

+0

Działa to dobrze tylko wtedy, gdy atrybutowi "x" przypisano typ niezmienny, a nie zmienny, ponieważ 'dict (C .__ dict __)' robi tylko płytką kopię, a nie głębię. – hynekcer

18

Właściwy sposób "kopia" klasa, jest, jak przypuszczenie, dziedziczenie:

class B(A): 
    pass 
+13

Możesz także zrobić używając 'type()', np. 'B = typ (" B ", (A,), {})' – kindall

+5

Dziedziczenie nie robi tego, co jest wymagane (induspendence wartości ARG), chyba że wartość jest również przypisana do B.ARG. – hynekcer

+0

@hynecker: czy mógłbyś wyjaśnić, co przez to rozumiesz? Myślę, że to odpowiada na pytanie OP: –

-1

Jeśli chcesz utworzyć tylko kolejną instancję klasy, a następnie po prostu zrobić to:

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

Stwórz własną konstruktora i po prostu powielić jak dokonaniu oryginalnego klasa:

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

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

Próbowałbym jednak uniknąć konieczności kopiowania obiektów.


sidenote: Użytkownik może również być w stanie uciec z robieniem:

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

Ale to jest chyba bardzo źle i nie należy tego robić. edit: faktycznie AttributeError: 'dictproxy' object has no attribute 'update' według PO

+0

Właściwie obiekt 'AttributeError: 'dictproxy' nie ma atrybutu 'update'' – I159

7

Można użyć funkcji fabrycznego:

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

A = get_A() 
B = get_A() 
2

myślę, że rozumieją znaczenie zmiennej statycznej tutaj. Każde miejsce, w którym zadeklarujesz zmienną poza metodą, a nie w postaci self.some_thing, zmienna będzie traktowana jako zmienna statyczna klasy (np. Twoja zmienna ARG tutaj). Zatem każdy obiekt (instancja) klasy, która zmienia zmienną statyczną, spowoduje zmianę wszystkich innych obiektów w tej samej klasie. Głębokość naprawdę spełnia tę funkcję.