85 votes

Comment copier une classe python ?

deepcopy de copy ne copie pas une classe :

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

>>> B = deepcopy(A)

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

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

>>> A.ARG = 2

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

Est-ce le seul moyen ?

 B(A):
    pass

77voto

Florian Brucker Points 2383

En général, l'héritage est la bonne voie à suivre, comme les autres affiches l'ont déjà souligné.

Cependant, si vous voulez vraiment recréer le même type avec un nom différent et sans héritage, vous pouvez le faire comme ceci :

 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'

Vous devez être prudent avec les valeurs d'attribut mutables :

 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]' (!)

28voto

David Robinson Points 33371

La bonne façon de "copier" une classe est, comme vous le supposez, l'héritage :

 class B(A):
    pass

23voto

James Points 1350

Vous pouvez utiliser une fonction d'usine :

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

A = get_A()
B = get_A()

8voto

willtalmadge Points 116

Comme l'a souligné Florian Brucker, il y a un problème avec les attributs de classe mutables. Vous ne pouvez pas non plus vous contenter de deepcopy(cls.__dict__) sur de nouveaux objets de style. J'ai fait ce qui suit pour résoudre ce problème pour ce que je fais. Je suis certain que quelqu'un d'assez déterminé pourrait briser ça. Mais, cela fonctionnera dans plus de cas.

 from copy import deepcopy
from typing import TypeVar

Cls = TypeVar('Cls')


# This type hint is a dirty lie to make autocomplete and static
# analyzers give more useful results. Crazy the stuff you can do
# with python...
def copy_class(cls: Cls) -> Cls:
    copy_cls = type(f'{cls.__name__}Copy', cls.__bases__, dict(cls.__dict__))
    for name, attr in cls.__dict__.items():
        try:
            hash(attr)
        except TypeError:
            # Assume lack of __hash__ implies mutability. This is NOT
            # a bullet proof assumption but good in many cases.
            setattr(copy_cls, name, deepcopy(attr))
    return copy_cls


def test_copy_class():
    class A(object):
        mutable_class_var = []

    ACopy = copy_class(A)

    a = A()
    acopy = ACopy()

    acopy.mutable_class_var.append(1)
    assert a.mutable_class_var == []
    assert A.mutable_class_var == []
    assert ACopy.mutable_class_var == [1]
    assert acopy.mutable_class_var == [1]

2voto

vutran Points 456

Je pense que vous comprenez mal le sens de variable statique ici. Partout où vous déclarez une variable en dehors d'une méthode et non sous la forme de self.some_thing , la variable sera considérée comme la variable statique de la classe (comme votre variable ARG ici). Ainsi, chaque objet ( instance ) de la classe qui modifie une variable statique entraînera la modification de tous les autres objets de la même classe. Le deepcopy fait vraiment le travail ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X