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

Comme pour Dernière fois, une note lors de l'interprétation de l'article ici.

Mixin (méthode de classe) avec héritage

Dans le texte original, cela s'appelle Mixin, mais honnêtement, cela ne me vient pas. Doit-elle être considérée comme une classe d'héritage uniquement qui fournit une certaine fonction (méthode) et n'est pas utilisée (= non instanciée) par elle-même?

Le code lui-même est presque le même que [Généralisation de l'usine en utilisant des arguments de longueur variable](http://qiita.com/FGtatsuro/items/9e45ee7a0e4165004dc0#Généralisation de l'usine en utilisant des arguments de longueur variable). Les différences sont les suivantes.

python


class FlyweightMixin(object):

    _instances = {}

    @classmethod    
    def get_instance(cls, *args, **kwargs):
		# _instance est une variable de classe et est réutilisée par toutes les classes qui héritent de cette classe.
        #argument(*args, **kwargs)Une classe héritée en tant que clé de dictionnaire pour distinguer les instances avec les mêmes classes mais différentes(cls)Doit également être utilisé.
        return cls._instances.setdefault((cls, args, tuple(kwargs.items())), cls(*args, **kwargs))

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

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


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

#Cas avec les mêmes arguments mais des classes différentes
#Classe héritée comme clé du dictionnaire(cls)Si vous n'utilisez pas, cette assertion échouera.
assert Hoge.get_instance('a', kwargs1='b') is not Piyo.get_instance('a', kwargs1='b')

Mixin avec héritage (méthode __new__)

Dans l'exemple précédent, "La classe FlyweightMixin est l'héritage uniquement ", mais si vous souhaitez la créer, vous pouvez créer une instance de la classe FlyweightMixin en utilisant FlyweightMixin (). Dans l'exemple suivant, le processus est transféré vers la méthode __new__ qui est toujours appelée lorsqu'une instance est créée, et une exception est levée dans la méthode __init__ qui est appelée après la méthode __new__. L'appel de FlyweightMixin () lève une exception, donc pour utiliser la classe FlyweightMixin, vous devez toujours hériter et remplacer la méthode __init __ dans la sous-classe.

python


class FlyweightMixin(object):

    _instances = {}

    def __init__(self, *args, **kwargs):
        raise NotImplementedError

    def __new__(cls, *args, **kwargs):
        # Python2,Fonctionne avec Python 3
        instance = super(type(cls), cls).__new__(cls)
        #Seul Python 3 fonctionne:Python2 ne prend pas en charge l'appel de super fonctions avec des arguments omis
        # instance = super().__new__(cls)
        #Seul Python2 fonctionne:Python3 est un objet.__new__Impossible d'accepter les arguments de longueur variable(Je ne sais pas pourquoi)
        # instance = super(type(cls), cls).__new__(cls, *args, **kwargs)
        return cls._instances.setdefault((cls, args, tuple(kwargs.items())), instance)

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

class Piyo(FlyweightMixin):
    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')

(Supplément) Valeur de retour de la méthode __new__

Normalement, la méthode __new__ renvoie une nouvelle instance de la classe donnée dans le premier argument. D'autre part, la méthode __new__ de FlyweightMixin enregistre l'instance créée dans le dictionnaire _instances et renvoie l'instance enregistrée à partir de la deuxième fois.

Mixin avec décorateur

Dans l'exemple suivant, la logique de modèle Flyweight qui a été donnée à la classe parente (FlyweightMixin) dans la méthode utilisant l'héritage est donnée au côté de la classe enfant à l'aide d'un décorateur. La fonction flyweight remplace la variable _instances (dictionnaire) et la méthode __new__ (objet fonction qui définit la logique du modèle Flyweight) pour l'objet de classe pris comme argument et le renvoie.

python


#Si vous n'en faites pas une méthode de classe avec la fonction classmethod, une erreur se produira dans Python2.
# (ref.) 
# http://chikatoike.hatenadiary.jp/entry/2013/07/31/125624
# http://momijiame.tumblr.com/post/67251294770/pythone
# https://docs.python.org/3/whatsnew/3.0.html#operators-and-special-methods
# (2015/02/27 Addendum)
#La fonction staticmethod était bien aussi. Consulter le document__new__La méthode statique est plus appropriée pour mettre en?
# (ref.) https://docs.python.org/3.3/reference/datamodel.html#object.__new__
@classmethod
def _get_instance(cls, *args, **kwargs):
    instance = super(type(cls), cls).__new__(cls)
    #Chaque classe est un dictionnaire(cls._instances)Élimine le besoin d'inclure des objets de classe dans les clés
    return cls._instances.setdefault((args, tuple(kwargs.items())), instance)


def flyweight(cls):
    #L'objet fonction affecté à l'attribut de l'objet classe est
    # Python2: unbound method(=Doit spécifier l'instance à lier à l'appel)
    # __new__Est implicitement appelée lors de l'instanciation
    #Ce qui est passé est un objet de classe(cls)Et une instance de cette classe(self)n'est pas
    # Python3:Rester en tant qu'objet de fonction
    cls._instances = {}
    print(_get_instance)
    cls.__new__ = _get_instance
    print(cls.__new__)
    return cls

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

# Piyo = flyweight(Piyo)Équivalent à
@flyweight
class Piyo(object):
    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')

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
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 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