Ändere das Fliegengewichtsmuster in Pythonic (?) (1)

Ein Memo, das den Artikel interpretiert, der von der Person neben mir unterrichtet wurde.

Fliegengewichtsmuster GoF treu

Eine Fabrik ist für ein Ziel definiert. Der folgende Code entspricht weitgehend dem Originalartikel, mit Änderungen an benannten Argumenten.

python


class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

class HogeFactory(object):
    def  __init__(self):
        self._instances = {}

    def get_instance(self, args1, kwargs1):
        if ((args1), (kwargs1)) not in self._instances:
            self._instances[((args1), (kwargs1))] = Hoge(args1, kwargs1=kwargs1)
        return self._instances[((args1), (kwargs1))]


class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

class PiyoFactory(object):
    def __init__(self):
        self._instances = {}

    def get_instance(self, args1, kwargs1='test1', kwargs2='test2'):
        if ((args1), (kwargs1, kwargs2)) not in self._instances:
            self._instances[((args1), (kwargs1, kwargs2))] = Piyo(args1, kwargs1=kwargs1, kwargs2=kwargs2)
        return self._instances[((args1), (kwargs1, kwargs2))]

hogeFactory = HogeFactory()
piyoFactory = PiyoFactory()

assert hogeFactory.get_instance(1, kwargs1=2) is hogeFactory.get_instance(1, kwargs1=2)
assert hogeFactory.get_instance(1, kwargs1=2) is not hogeFactory.get_instance(1, kwargs1=3)
assert piyoFactory.get_instance('a', kwargs1='b', kwargs2='c') is piyoFactory.get_instance('a', kwargs1='b', kwargs2='c')
assert piyoFactory.get_instance('a', kwargs1='b', kwargs2='c') is not piyoFactory.get_instance('a', kwargs1='b', kwargs2='d')

Werksgeneralisierung mit Argumenten variabler Länge

Der Grund, warum eine Factory für ein Ziel benötigt wurde, war, dass die Signatur des Konstruktors jedes Ziels unterschiedlich war = die Signatur der Methode "get_instance" war unterschiedlich. Sie können Pythons Argumente mit variabler Länge verwenden, um Unterschiede in den Signaturen zu absorbieren.

python


class FlyweightFactory(object):
    def __init__(self, cls):
        self._instances = {}
        self._cls = cls

    def get_instance(self, *args, **kwargs):
        return self._instances.setdefault((args, tuple(kwargs.items())), self._cls(*args, **kwargs))

class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

hogeFactory = FlyweightFactory(Hoge)
piyoFactory = FlyweightFactory(Piyo)

assert hogeFactory.get_instance(1, kwargs1=2) is hogeFactory.get_instance(1, kwargs1=2)
assert hogeFactory.get_instance(1, kwargs1=2) is not hogeFactory.get_instance(1, kwargs1=3)
assert piyoFactory.get_instance('a', kwargs1='b', kwargs2='c') is piyoFactory.get_instance('a', kwargs1='b', kwargs2='c')
assert piyoFactory.get_instance('a', kwargs1='b', kwargs2='c') is not piyoFactory.get_instance('a', kwargs1='b', kwargs2='d')

Fabrikdekorateur (Klasse)

Wenn Sie die oben genannte "Flyweight Factory" dekorieren, können Sie sie einfacher schreiben.

python


class Flyweight(object):
    def __init__(self, cls):
        self._instances = {}
        self._cls = cls

    def __call__(self, *args, **kwargs):
        return self._instances.setdefault((args, tuple(kwargs.items())), self._cls(*args, **kwargs))

@Flyweight
class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

@Flyweight
class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

assert Hoge(1, kwargs1=2) is Hoge(1, kwargs1=2)
assert Hoge(1, kwargs1=2) is not Hoge(1, kwargs1=3)
assert Piyo('a', kwargs1='b', kwargs2='c') is Piyo('a', kwargs1='b', kwargs2='c')
assert Piyo('a', kwargs1='b', kwargs2='c') is not Piyo('a', kwargs1='b', kwargs2='d')

Der Dekorateur wird aufgerufen, indem das angehängte Ziel als Argument verwendet wird. Der diesem Prozess entsprechende Code kann ohne Verwendung eines Dekorateurs wie folgt geschrieben werden. Anstatt "get_instance" aufzurufen, gibt es einen Unterschied beim Lesen der Flyweight-Instanz als Funktion, aber Sie können sehen, dass sie sich nicht so stark vom vorherigen Snippet unterscheidet.

(ref. http://docs.python.jp/3.4/reference/datamodel.html#object.call)

python


class Flyweight(object):
    def __init__(self, cls):
        self._instances = {}
        self._cls = cls

    def __call__(self, *args, **kwargs):
        return self._instances.setdefault((args, tuple(kwargs.items())), self._cls(*args, **kwargs))

class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

# Hoge,Nehmen Sie Piyo als Argument,Erstellen Sie eine Flyweight-Instanz.
Hoge = Flyweight(Hoge)
Piyo = Flyweight(Piyo)

assert Hoge(1, kwargs1=2) is Hoge(1, kwargs1=2)
assert Hoge(1, kwargs1=2) is not Hoge(1, kwargs1=3)
assert Piyo('a', kwargs1='b', kwargs2='c') is Piyo('a', kwargs1='b', kwargs2='c')
assert Piyo('a', kwargs1='b', kwargs2='c') is not Piyo('a', kwargs1='b', kwargs2='d')

Fabrikdekorateur (näher)

Darüber hinaus ist es nicht erforderlich, eine Klasse zu sein, solange sie aufrufbar ist. Dies ist die Implementierung mit dem folgenden Abschluss.

python


def flyweight(cls):
    instances = {}
    return lambda *args, **kwargs: instances.setdefault((args, tuple(kwargs.items())), cls(*args, **kwargs))

@flyweight
class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

@flyweight
class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

assert Hoge(1, kwargs1=2) is Hoge(1, kwargs1=2)
assert Hoge(1, kwargs1=2) is not Hoge(1, kwargs1=3)
assert Piyo('a', kwargs1='b', kwargs2='c') is Piyo('a', kwargs1='b', kwargs2='c')
assert Piyo('a', kwargs1='b', kwargs2='c') is not Piyo('a', kwargs1='b', kwargs2='d')

Der entsprechende Code ohne Dekorateur sieht folgendermaßen aus:

python


def flyweight(cls):
    instances = {}
    return lambda *args, **kwargs: instances.setdefault((args, tuple(kwargs.items())), cls(*args, **kwargs))

class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

Hoge = flyweight(Hoge)
Piyo = flyweight(Piyo)

assert Hoge(1, kwargs1=2) is Hoge(1, kwargs1=2)
assert Hoge(1, kwargs1=2) is not Hoge(1, kwargs1=3)
assert Piyo('a', kwargs1='b', kwargs2='c') is Piyo('a', kwargs1='b', kwargs2='c')
assert Piyo('a', kwargs1='b', kwargs2='c') is not Piyo('a', kwargs1='b', kwargs2='d')

Diese Methode ist sehr intelligent, hat jedoch den Nachteil, dass Sie keine Unterklasse der Klasse "Hoge" / "Piyo" erstellen können. Dies liegt daran, dass das "Hoge" / "Piyo" keine Klasse mehr ist, sondern ein Funktionsobjekt, wie Sie im Code sehen können, der keine Dekoratoren verwendet. Daher führt der folgende Code zu einem Fehler.

python


def flyweight(cls):
    instances = {}
    return lambda *args, **kwargs: instances.setdefault((args, tuple(kwargs.items())), cls(*args, **kwargs))

@flyweight
class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

@flyweight
class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

#Hoge ist keine Klasse mehr und kann nicht vererbt werden
class Hoge2(Hoge):
    def __init__(self, args1, kwargs1='test1'):
        super().__init__(args1, kwargs1=kwargs1)

In dem Sinne, dass "Hoge" / "Piyo" aufgrund des Dekorateurs keine Klasse mehr ist, ändert es sich nicht, selbst wenn der Dekorateur durch eine Klasse ausgedrückt wird, aber es gibt eine Instanz der "Flyweight" -Klasse, die die "Hoge" / "Piyo" -Klasse ersetzt. Es ist das Miso, das die ursprüngliche Klasse enthält. Daher kann es mit dem folgenden Code in Unterklassen unterteilt werden.

python


class Flyweight(object):
    def __init__(self, cls):
        self._instances = {}
        self._cls = cls

    def __call__(self, *args, **kwargs):
        return self._instances.setdefault((args, tuple(kwargs.items())), self._cls(*args, **kwargs))

@Flyweight
class Hoge(object):
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

@Flyweight
class Piyo(object):
    def __init__(self, args1, kwargs1, kwargs2):
        self.args1 = args1
        self.kwargs1 = kwargs1
        self.kwargs2 = kwargs2

# Hoge(Die Entität ist eine Flyweight-Instanz)Ist eine Instanzvariable, die die ursprüngliche Klasse enthält_Habe cls
class Hoge2(Hoge._cls):
    def __init__(self, args1, kwargs1='test1'):
        super().__init__(args1, kwargs1=kwargs1)

Recommended Posts

Ändere das Fliegengewichtsmuster in Pythonic (?) (3)
Ändere das Fliegengewichtsmuster in Pythonic (?) (2)
Ändere das Fliegengewichtsmuster in Pythonic (?) (1)
[Python] Ändere das Alphabet in eine Zahl
Lernen Sie das Designmuster "Flyweight" in Python
Skript zum Ändern der Beschreibung von Fasta
[Python] So ändern Sie das Datumsformat (Anzeigeformat)
Ändern Sie den Dezimalpunkt der Protokollierung von, nach.
Fliegengewichtsmuster in Java
Der Weg nach Pythonista
Über das Besuchermuster
Der Weg nach Djangoist
[Python] Ändern Sie die Cache-Steuerung von Objekten, die in den Cloud-Speicher hochgeladen wurden
Ändern Sie das Gebietsschema von Amazon Linux mithilfe der Lineinfile von Ansible in Japan
[Python] Ändern Sie den Namen der Bilddatei in eine Seriennummer
Ändern Sie das Standardausgabeziel in eine Datei in Python
Eine Einführung in die Objektorientierung: Ändern Sie den internen Status eines Objekts
Ich möchte mit Numpy die japanische Flagge in die Palau-Flagge ändern
Ändern Sie die Lautstärke von Pepper entsprechend der Umgebung (Ton).
Ändern Sie die Meldung, die beim Anmelden bei Raspberry Pi angezeigt wird
Ändern Sie das Installationsziel, wenn --user zu pip hinzugefügt wird
Verwendung des Generators
Punkt entsprechend dem Bild
Ändern Sie das Thema von Jupyter
Ändern Sie den Stil von matplotlib
So ändern Sie die Python-Version
Wie benutzt man den Dekorateur?
So erhöhen Sie die Achse
So starten Sie die erste Projektion
So ändern Sie die Protokollstufe von Azure SDK für Python
So ändern Sie die Farbe nur der mit Tkinter gedrückten Taste
Ändern Sie die Y-Achsenskala von Matplotlib in die Exponentialschreibweise (10-te Potenzschreibweise).
Fühlen Sie sich frei, das Legendenlabel mit Seaborn in Python zu ändern
[Los] Erstellen Sie einen CLI-Befehl, um die Erweiterung des Bildes zu ändern
Ändern Sie die Bash-Eingabeaufforderung zur einfachen Anzeige in eine einfache Farbe
Ich habe zusammengefasst, wie die Boot-Parameter von GRUB und GRUB2 geändert werden
Ändern Sie die aktive Version in Pyenv von Anaconda in einfaches Python