Précédent, Précédent, [Ici](http: // yloiseau) Une note sur l'interprétation de l'article dans .net / articles / DesignPatterns / flyweight /).
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')
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