Changez le modèle Flyweight en Pythonic (?) (3)

Précédent, Précédent, [Ici](http: // yloiseau) Une note sur l'interprétation de l'article dans .net / articles / DesignPatterns / flyweight /).

Modèle de poids mouche utilisant une métaclasse (sous-classe de la classe de type)

Avant la méthode utilisant la méta-classe, je vais aborder la classe préalable type. La classe type est utilisée lors de la création d'une définition de classe (= objet de classe).

python


def methodA(self):
    print('methodA')

#Nom de classe, classe parente(Plusieurs spécifications sont possibles), Espace de nom(Exprimé par un dictionnaire, ici'methodA'La méthode Une fonction est liée à)Prend comme argument
#Créer un objet de classe
ClassA = type('ClassA', (object,), {'methodA': methodA})
a = ClassA()
a.methodA()

#Équivalent à la définition suivante
# class ClassA(object):
#     def methodA(self):
#        print('methodA')

Comme mentionné ci-dessus, «type» est une classe. Par conséquent, des sous-classes peuvent être créées. Les sous-classes peuvent être utilisées pour créer des objets de classe au lieu de la classe type, et vous pouvez ajouter un traitement lors de la création d'objets de classe en remplaçant les méthodes __new__ et __init__.

python


def methodA(self):
    print('methodA')

class Meta(type):
    def __new__(cls, name, bases, namespace):
        #Vous pouvez insérer un traitement supplémentaire lors de la création d'un objet de classe
        print('hoge')
        return super().__new__(cls, name, bases, namespace)

#Meta class au lieu de type class(=Une sous-classe de la classe type)Peut être utilisé
ClassA = Meta('ClassA', (object,), {'methodA': methodA})
a = ClassA()
a.methodA()

Si vous souhaitez utiliser autre chose que la classe de type lors de la création d'un objet de classe dans la syntaxe de définition de classe normale, utilisez le mot-clé metaclass dans Python3. La classe spécifiée à ce moment est appelée une méta-classe.

python


class Meta(type):
    def __new__(cls, name, bases, namespace):
        #Vous pouvez insérer un traitement supplémentaire lors de la création d'un objet de classe
        print('hoge')
        return super().__new__(cls, name, bases, namespace)

class ClassA(object, metaclass=Meta):
#Spécification de la métaclasse Python2
#class ClassA(object):
#    __metaclass__ =Meta
    def methodA(self):
        print('methodA')

a = ClassA()
a.methodA()

Voici un exemple d'insertion de la logique de modèle Flyweight lors de la création d'un projet de classe, en utilisant la propriété de la métaclasse que "le traitement peut être ajouté lors de la création d'un objet de classe".

python


class MetaFlyweight(type):
    def __new__(cls, name, bases, namespace):
        #de classe de type__new__La méthode renvoie un objet de classe
        clsobj = type.__new__(cls, name, bases, namespace)

        clsobj._instances = {}
        def _get_instance(cls, *args, **kargs):
            instance = super(cls, cls).__new__(cls)
            return cls._instances.setdefault(
                    (args, tuple(kargs.items())), instance)
        #Cela fonctionne sans en faire une méthode statique, mais en faire une méthode statique selon la description suivante
        # (ref.) https://docs.python.org/3.3/reference/datamodel.html#object.__new__
        clsobj.__new__ = staticmethod(_get_instance)
        return clsobj

class Hoge(object, metaclass=MetaFlyweight):
#Spécification de la métaclasse Python2
#class Hoge(object):
#    __metaclass__ = MetaFlyweight
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

class Piyo(object, metaclass=MetaFlyweight):
#Spécification de la métaclasse Python2
#class Piyo(object):
#    __metaclass__ = MetaFlyweight
    def __init__(self, args1, kwargs1):
        self.args1 = args1
        self.kwargs1 = kwargs1

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') is Piyo('a', kwargs1='b')
assert Piyo('a', kwargs1='b') is not Piyo('a', kwargs1='c')
assert Hoge('a', kwargs1='b') is not Piyo('a', kwargs1='b')
assert Hoge('a', kwargs1='b') is not Piyo('a', kwargs1='b')

Modèle de poids mouche (fonction) utilisant une métaclasse

Cependant, il n'est pas toujours nécessaire de générer une sous-classe de la classe type. Lorsqu'un objet de classe est créé, la classe de type à laquelle sont attribués "nom de classe (chaîne de caractères)", "classe parent (taple)" et "espace de noms (dictionnaire)" est appelée. Cependant, ce qui est nécessaire ici n'est pas une classe (ou sous-classe) type, mais un" objet appelable qui reçoit les trois arguments ci-dessus. " Par conséquent, il est également possible de spécifier la fonction dans la métaclasse comme suit.

python


def meta_flyweight(name, bases, namespace):
    clsobj = type(name, bases, namespace)

    clsobj._instances = {}
    def _get_instance(cls, *args, **kargs):
        instance = super(cls, cls).__new__(cls)
        return cls._instances.setdefault(
                (args, tuple(kargs.items())), instance)
    #Cela fonctionne sans en faire une méthode statique, mais en faire une méthode statique selon la description suivante
    # (ref.) https://docs.python.org/3.3/reference/datamodel.html#object.__new__
    clsobj.__new__ = staticmethod(_get_instance)
    return clsobj

class Hoge(object, metaclass=meta_flyweight):
#Spécification de la métaclasse Python2
#class Hoge(object):
#    __metaclass__ = meta_flyweight
    def __init__(self, args1, kwargs1='test1'):
        self.args1 = args1
        self.kwargs1 = kwargs1

class Piyo(object, metaclass=meta_flyweight):
#Spécification de la métaclasse Python2
#class Piyo(object):
#    __metaclass__ = meta_flyweight
    def __init__(self, args1, kwargs1):
        self.args1 = args1
        self.kwargs1 = kwargs1

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') is Piyo('a', kwargs1='b')
assert Piyo('a', kwargs1='b') is not Piyo('a', kwargs1='c')
assert Hoge('a', kwargs1='b') is not Piyo('a', kwargs1='b')
assert Hoge('a', kwargs1='b') is not Piyo('a', kwargs1='b')

Recommended Posts

Changez le modèle Flyweight en Pythonic (?) (3)
Changez le modèle Flyweight en Pythonic (?) (2)
Changez le modèle Flyweight en Pythonic (?) (1)
[Python] Changer l'alphabet en nombre
Apprenez le modèle de conception "Flyweight" en Python
Script pour changer la description de fasta
[Python] Comment changer le format de la date (format d'affichage)
Modifiez le point décimal de la journalisation de, à.
Modèle de poids mouche en Java
La route vers Pythonista
À propos du modèle de visiteur
La route vers Djangoist
[Python] Modifier le contrôle du cache des objets téléchargés sur Cloud Storage
Changez les paramètres régionaux Amazon Linux au Japon à l'aide du fichier lineinfile d'Ansible
[python] Remplacez le nom du fichier image par un numéro de série
Changer la destination de sortie standard en un fichier en Python
Une introduction à l'orientation des objets - changeons l'état interne d'un objet
Je veux changer le drapeau japonais en drapeau des Palaos avec Numpy
Changer le volume de Pepper en fonction de l'environnement environnant (son)
Changer le message affiché lors de la connexion à Raspberry Pi
Changez la destination d'installation lorsque --user est ajouté à pip
Comment utiliser le générateur
Comment changer la disposition de Jupyter
Point selon l'image
La route pour télécharger Matplotlib
Changer le thème de Jupyter
Changer le style de matplotlib
Comment changer la version de Python
Comment utiliser le décorateur
Comment augmenter l'axe
Comment démarrer la première projection
Comment modifier le niveau de journalisation d'Azure SDK pour Python
Comment changer la couleur du seul bouton pressé avec Tkinter
Changer l'échelle de l'axe Y de Matplotlib en notation exponentielle (10 Nth power notation)
N'hésitez pas à changer l'étiquette de légende avec Seaborn en python
[Go] Créez une commande CLI pour changer l'extension de l'image
Changez l'invite de bash en une couleur simple pour une visualisation facile
J'ai résumé comment changer les paramètres de démarrage de GRUB et GRUB2
Changer la version active dans Pyenv d'Anaconda en Python ordinaire