6
6
import weakref
7
7
8
8
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
+
9
46
class Card (object ):
10
47
11
48
"""The object pool. Has builtin reference counting"""
@@ -27,6 +64,15 @@ def __new__(cls, value, suit):
27
64
def __repr__ (self ):
28
65
return "<Card: %s%s>" % (self .value , self .suit )
29
66
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
+
30
76
if __name__ == '__main__' :
31
77
# comment __new__ and uncomment __init__ to see the difference
32
78
c1 = Card ('9' , 'h' )
@@ -42,6 +88,25 @@ def __repr__(self):
42
88
c3 = Card ('9' , 'h' )
43
89
print (hasattr (c3 , 'temp' ))
44
90
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
+
45
110
### OUTPUT ###
46
111
# (<Card: 9h>, <Card: 9h>)
47
112
# (True, True)
0 commit comments