As with previous, a memo when interpreting the article here.
In the original text, it is called Mixin, but honestly, it doesn't come out. Should we think of it as an inheritance-only class that provides a certain function (method) and does not use it alone (= does not instantiate)?
The code itself is almost the same as [Generalization of factory using variadic arguments](http://qiita.com/FGtatsuro/items/9e45ee7a0e4165004dc0#Generalization of factory using variadic arguments). The differences are as follows.
--The functionality provided by FlyweightFactory is used from the Hoge
/ Piyo
class by inheritance.
--Use classes as well as variadic arguments as dictionary keys
python
class FlyweightMixin(object):
_instances = {}
@classmethod
def get_instance(cls, *args, **kwargs):
# _instance is a class variable and is reused by all classes that inherit from this class.
#argument(*args, **kwargs)Classes inherited as dictionary keys to distinguish between instances with the same but different classes(cls)Must also be used.
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')
#Cases with the same arguments but different classes
#Class inherited as a dictionary key(cls)If you are not using, this assertion will fail.
assert Hoge.get_instance('a', kwargs1='b') is not Piyo.get_instance('a', kwargs1='b')
__new__
method)In the previous example, "The FlyweightMixin
class is inheritance only ", but if you want to create it, you can create an instance of the FlyweightMixin class by doingFlyweightMixin ()
.
In the following example, the process is transferred to the __new__
method that is always called when creating an instance, and an exception is thrown in the __init__
method that is called after the __new__
method.
Calling FlyweightMixin ()
throws an exception, so in order to use the FlyweightMixin
class, you must always inherit and override the __init __
method in your subclass.
python
class FlyweightMixin(object):
_instances = {}
def __init__(self, *args, **kwargs):
raise NotImplementedError
def __new__(cls, *args, **kwargs):
# Python2,Works with Python 3
instance = super(type(cls), cls).__new__(cls)
#Only Python 3 works:Python2 does not support calling super functions with arguments omitted
# instance = super().__new__(cls)
#Only Python2 works:Python3 is object.__new__Cannot accept variadic arguments(I don't know why)
# 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')
__new__
methodNormally, the __new__
method returns a new instance of the class given in the first argument. On the other hand, the __new__
method of FlyweightMixin
saves the created instance in the _instances
dictionary, and returns the saved instance from the second time onward.
In the following example, the logic of the Flyweight pattern that was given to the parent class (FlyweightMixin
) in the method using inheritance is given to the child class side using the decorator. The flyweight
function substitutes the _instances
variable (dictionary) and the __new__
method (function object that defines the logic of the Flyweight pattern) for the class object taken as an argument and returns it.
python
#If you do not make it a class method by the classmethod function, an error will occur in 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)
#The staticmethod function was fine too. Looking at the document__new__The static method is more appropriate to put in?
# (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)
#Each class is a dictionary(cls._instances)Eliminates the need to include a class object in the key
return cls._instances.setdefault((args, tuple(kwargs.items())), instance)
def flyweight(cls):
#The function object assigned to the attribute of the class object is
# Python2: unbound method(=You must specify the instance to bind on call)
# __new__Is implicitly called when instantiating
#What is passed is a class object(cls)And an instance of that class(self)is not
# Python3:Remain as a function object
cls._instances = {}
print(_get_instance)
cls.__new__ = _get_instance
print(cls.__new__)
return cls
# Hoge = flyweight(Hoge)Equivalent to
@flyweight
class Hoge(object):
def __init__(self, args1, kwargs1='test1'):
self.args1 = args1
self.kwargs1 = kwargs1
# Piyo = flyweight(Piyo)Equivalent to
@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