wake-up-neo.com

Konstruktor in Python kopieren?

Gibt es einen Kopierkonstruktor in python? Wenn nicht, was würde ich tun, um etwas Ähnliches zu erreichen?

Die Situation ist, dass ich eine Bibliothek verwende und eine der Klassen dort um zusätzliche Funktionen erweitert habe und die Objekte, die ich aus der Bibliothek erhalte, in Instanzen meiner eigenen Klasse konvertieren möchte.

77
Zitrax

Ich denke du willst das Kopiermodul

import copy

x = copy.copy(y)        # make a shallow copy of y
x = copy.deepcopy(y)    # make a deep copy of y

sie können das Kopieren auf die gleiche Weise steuern wie pickle .

61
Tom Dunham

In python kann der Kopierkonstruktor mit Standardargumenten definiert werden. Nehmen wir an, Sie möchten, dass der normale Konstruktor die Funktion non_copy_constructor(self) ausführt und der Kopierkonstruktor copy_constructor(self, orig). Dann können Sie Folgendes tun:

class Foo:
    def __init__(self, orig=None):
        if orig is None:
            self.non_copy_constructor()
        else:
            self.copy_constructor(orig)
    def non_copy_constructor(self):
        # do the non-copy constructor stuff
    def copy_constructor(self, orig):
        # do the copy constructor

a=Foo()  # this will call the non-copy constructor
b=Foo(a) # this will call the copy constructor
22
qwerty9967

Ein einfaches Beispiel für meine übliche Implementierung eines Kopierkonstruktors:

import copy

class Foo:

  def __init__(self, data):
    self._data = data

  @classmethod
  def from_foo(cls, class_instance):
    data = copy.deepcopy(class_instance._data) # if deepcopy is necessary
    return cls(data)
14
Godsmith

In Ihrer Situation würde ich vorschlagen, eine Klassenmethode (oder eine statische Methode oder eine separate Funktion) zu schreiben, die eine Instanz der Klasse der Bibliothek als Argument verwendet und eine Instanz Ihrer Klasse mit allen anwendbaren Attributen zurückgibt, die kopiert wurden.

11
David Z

Aufbauend auf @ Godsmiths Gedankengang und Ansprechen von @ Zitrax 'Bedürfnis (glaube ich), die Daten für alle Attribute innerhalb des Konstruktors zu kopieren:

class ConfusionMatrix(pd.DataFrame):
    def __init__(self, df, *args, **kwargs):
        try:
            # Check if `df` looks like a `ConfusionMatrix`
            # Could check `isinstance(df, ConfusionMatrix)`
            # But might miss some "ConfusionMatrix-elligible" `DataFrame`s
            assert((df.columns == df.index).all())
            assert(df.values.dtype == int)
            self.construct_copy(df, *args, **kwargs)
            return
        except (AssertionError, AttributeError, ValueError):
            pass
        # df is just data, so continue with normal constructor here ...

    def construct_copy(self, other, *args, **kwargs):
        # construct a parent DataFrame instance
        parent_type = super(ConfusionMatrix, self)
        parent_type.__init__(other)
        for k, v in other.__dict__.iteritems():
            if hasattr(parent_type, k) and hasattr(self, k) and getattr(parent_type, k) == getattr(self, k):
                continue
            setattr(self, k, deepcopy(v))

Diese ConfusionMatrix Klasse erbt ein pandas.DataFrame und fügt eine Menge anderer Attribute und Methoden hinzu, die neu berechnet werden müssen, es sei denn, die Matrixdaten von other können kopiert werden. Auf der Suche nach einer Lösung bin ich auf diese Frage gestoßen.

4
hobs

Ich habe eine ähnliche Situation, die sich darin unterscheidet, dass die neue Klasse nur Attribute kopieren muss. Auf diese Weise könnte @ meisterluks "copy_constructor" -Methode lauten:

from copy import deepcopy
class Foo(object):
    def __init__(self, myOne=1, other=None):
    self.two = 2
    if other <> None:
        assert isinstance(other, Foo), "can only copy instances of Foo"
        self.__dict__ = deepcopy(other.__dict__)
    self.one = myOne

def __repr__(self):
    out = ''
    for k,v in self.__dict__.items():
        out += '{:>4s}: {}, {}\n'.format(k,v.__class__,v)
    return out

def bar(self):
    pass

foo1 = Foo()
foo2 = Foo('one', foo1)

print '\nfoo1\n',foo1
print '\nfoo2\n',foo2

Die Ausgabe:

foo1
 two: <type 'int'>, 2
 one: <type 'int'>, 1


foo2
 two: <type 'int'>, 2
 one: <type 'str'>, one
2
upandacross