66import weakref
77
88
9+ class FlyweightMeta (type ):
10+ def __new__ (mcs , name , parents , dct ):
11+ """
12+
13+ :param name: class name
14+ :param parents: class parents
15+ :param dct: dict: includes class attributes, class methods,
16+ static methods, etc
17+ :return: new class
18+ """
19+
20+ # set up instances pool
21+ dct ['pool' ] = weakref .WeakValueDictionary ()
22+ return super (FlyweightMeta , mcs ).__new__ (mcs , name , parents , dct )
23+
24+ @staticmethod
25+ def _serialize_params (cls , * args , ** kwargs ):
26+ """Serialize input parameters to a key.
27+ Simple implementation is just to serialize it as a string
28+
29+ """
30+ args_list = map (str , args )
31+ args_list .extend ([str (kwargs ), cls .__name__ ])
32+ key = '' .join (args_list )
33+ return key
34+
35+ def __call__ (cls , * args , ** kwargs ):
36+ key = FlyweightMeta ._serialize_params (cls , * args , ** kwargs )
37+ pool = getattr (cls , 'pool' , {})
38+
39+ instance = pool .get (key )
40+ if not instance :
41+ instance = super (FlyweightMeta , cls ).__call__ (* args , ** kwargs )
42+ pool [key ] = instance
43+ return instance
44+
45+
946class Card (object ):
1047
1148 """The object pool. Has builtin reference counting"""
@@ -27,6 +64,15 @@ def __new__(cls, value, suit):
2764 def __repr__ (self ):
2865 return "<Card: %s%s>" % (self .value , self .suit )
2966
67+
68+ class Card2 (object ):
69+ __metaclass__ = FlyweightMeta
70+
71+ def __init__ (self , * args , ** kwargs ):
72+ # print('Init {}: {}'.format(self.__class__, (args, kwargs)))
73+ pass
74+
75+
3076if __name__ == '__main__' :
3177 # comment __new__ and uncomment __init__ to see the difference
3278 c1 = Card ('9' , 'h' )
@@ -42,6 +88,25 @@ def __repr__(self):
4288 c3 = Card ('9' , 'h' )
4389 print (hasattr (c3 , 'temp' ))
4490
91+ # Tests with metaclass
92+ instances_pool = getattr (Card2 , 'pool' )
93+ cm1 = Card2 ('10' , 'h' , a = 1 )
94+ cm2 = Card2 ('10' , 'h' , a = 1 )
95+ cm3 = Card2 ('10' , 'h' , a = 2 )
96+
97+ assert (cm1 == cm2 ) != cm3
98+ assert (cm1 is cm2 ) is not cm3
99+ assert len (instances_pool ) == 2
100+
101+ del cm1
102+ assert len (instances_pool ) == 2
103+
104+ del cm2
105+ assert len (instances_pool ) == 1
106+
107+ del cm3
108+ assert len (instances_pool ) == 0
109+
45110### OUTPUT ###
46111# (<Card: 9h>, <Card: 9h>)
47112# (True, True)
0 commit comments