Design Patterns and Python
From the Gang of Four,
a flyweight is a shared object that
can be used in multiple contexts simultaneously and must be
independent of its context. Thus, only sharable state (intrinsic) must
be stored in the flyweight object itself, the context dependant state
(extrinsic) being kept separately and passed to the flyweight when
Here, we will only consider the flyweight creation mechanic, that is
managing shared objects, and thus
only deal with intrinsic state. This pattern is usually used when the
application needs a large number of instances of the same object having the
same intrinsic state, whose extrinsic state can be computed (or its storage
space is low), in order to limit the memory used by these objects.
The implementation presented in the GoF uses a factory class to create and manage flyweight instances, needing a specific factory for each flyweight interface. In this case, the factory class keep track of already created instances, and delegates the instances creation if needed to the flyweight class itself. This is the first approach presented here. However, this approach, being well suited to static languages (like Java or C++), is a too heavy one for dynamic languages like Python. Indeed, thanks to the Python duck typing, the factory mechanic can also be added to the class itself, using inheritance or dynamic class modification, which allow for a more generic approach. Language aspects such as decorators, multiple inheritance and mixins, and metaclasses make such approaches quite elegant to implement and easy to use.
The code snippets presented here are not usable as-is, since some aspects are not taken into account (e.g. subclassing a flyweight). See the discussion part for more details.
Strict Gang of Four implementation
This is a quite strict direct implementation of the pattern as described in the GoF, without using some nice features of Python. This is how this could be implemented in a static and strongly typed language.
However, since Python is dynamically typed and classes are first class citizen
objects, this approach can easily be generalized to be more generic. By using
*args magic in the
get_instance method, instead
of the explicit constructor parameters, and passing the flyweight class
as a factory constructor parameter, the factory itself can be generic, that is
independent of the flyweight object class, leading to the following
Gang of Four Version
This version is just a more pythonic version of the GoF one. By using the
*args magic and passing the class to be instantiated to the factory
constructor, there is no need to create a specific factory for each
Indeed, there is no need for the Abstract Factory pattern, since
classes, as first class objects, can be passed as parameters.
The factory is therefore generic using parametric polymorphism.
The class to be
instantiated by the factory is therefore not hardcoded, kept in the
attribute, and directly called in
*args magic allow the functions or methods to accept variable
get_instance can therefore accept any arguments
that are passed as is to the
_cls class to create the instance if
One more difference with the previous code is the use of
dict method does just what the test
did, that is, set the value of the corresponding key if it does not exists, and
return the value. Since
args is a list, we just need to convert it
to a tuple to use it as dict key (since keys must be immutable).
Wrapping Decorator Version
The next step is the use of the
__call__ special method. Every
instance (whatever the type) having a
__call__ method is
callable, that is can be used as a function. By renaming
__call__, we can thus instantiate
SpamFactory(1, 2) directly.
However, the global instantiation of
SpamFactory is not as elegant as it could be.
Indeed, since the instance is directly called to obtain an
instance (we don’t use
get_instance anymore), from the user
point of view, it behave like the
Spam class itself. Moreover, in
this pattern spirit, the
Spam class should
not be called (instantiated) directly to guaranty that we get the same
instances. One way would be to mask the
Spam class by replacing it
Spam = FlyweightFactory(Spam).
The flyweight machinery is therefore transparent to the user; but the
have to be instantiated. Hopefully, this is exactly what class
decorators are for.
Python’s decorators are high order callables, that is a callable
taking a callable as parameter and returning a callable; these callable can be
functions, a classes, etc. This is exactly the behaviour of our previous
FlyweightFactory class. Moreover, some syntactic sugar allow to
easily replace a callable with the decorated one, masking the original: the
In this code, the
@flyweight decoration is equivalent to the
Spam = flyweight(Spam).
Functional Wrapping Decorator
This begin to be quite usable. However, we can note that the
flyweight class corresponds to the method object pattern.
In functional languages, this pattern can be simply
implemented using a closure (see method
Here, the instances dictionary and the class to be instantiated are closed
in the lambda function definition instead of keeping them in objects
attributes. The resulting decorated class (e.g.
Spam) is actually
a closure wrapping the original class, that when called create a new instance
if needed and returns it.
Note how this last generic decorator approach is concise, elegant an easy to use compared to the specific original one.
Despite the zen of Python stating that
there should be one— and
preferably only one —obvious way to do it, the decorator approach is
not the only one that can be generic and elegant in python. One of them is the
mixin approach we will now examine.
GoF Mixin Version
Until then, we have had a delegation approach, creating a class or a
function that wraps the actual class, keeping track of instances and delegating
the intantiation. However, a approach similar to the singleton
pattern, i.e. keeping the list of instances in a static attribute of
the class, can be used. In this case, the factory method
get_instance is a static one, the default constructor beeing
private to ensure that the user use this method to create instance.
In python vocabulary, this static method is called a class method,
since the class is the implicit first argument (python static methods do not
have implicit arguments), and is defined using the
Again, thanks to the
*args magic and the dynamic typing
of the instances dictionary content, we can generalize this to avoid to add the
_instances class attribute and the
class method to each class we want to be flyweight.
Here, we use inheritance to add the class properties to the
flyweight classes. The
FlyweightMixin class is a mixin,
since it only implement specific functionalities (the flyweight machinery), and
is not a complete class on its own.
dictionary is defined in the mixin, it is a shared attribute among all classes
using it, so the previous code for
get_instance must be modified.
Indeed, the constructor arguments are not enough to identify the instance, we
also need to know its class. An other solution is to redefine the
_instances class attribute in every class using the mixin, but it
is more tedious and error prone. Since
get_instance is a class
method, its first argument is the class itself (not the mixin thanks to
polymorphism and dynamic dispatch), it is easy to add it to the dictionary
key. This is checked in the sample code by the last
cls parameter is also used to instantiate the
class. Note that here, it is a implicit parameter of the class method by
polymorphism, whereas is the delegation version, it was a parameter of the
However, this version is not fully satisfactory, since nothing prevents the
user to directly instantiate the class, bypassing the flyweight, since the
__init__ can’t be private. Actually,
__init__ is just the second step in the instantiation process, the
one initializing the instance
self (hence its name), the first one (the creation of
the instance itself) occurring in the special class method
By moving the flyweight logic from
__new__, we can prevent this bypassing. Moreover, since the
flyweight logic invocation is now transparent, we have a more readable syntax.
Since we are overriding
__new__, the instantiation must call
the super class method (here
object) to avoid a circular call. The
super allow better extensibility than
object.__new__(cls, *args, **kargs). Note that since
__new__ is a special method defined to be a class method, the
@classmethod decorator is no longer necessary.
Modifying Decorator Version
Besides inheritance, the class properties can be added to the flyweight by directly modifying the class itself. Indeed, since python is a fully dynamic language, classes can be changed at runtime. This is a more dynamic, less restrictive and, in my sense, more elegant approach than the mixin one, since it can be used on existing classes (e.g. third party classes), and can easily be accomplished using a class decorator.
Contrary to the wrapping decorator,
the function that create instances (
defined outside the decorator instead of in a anonymous function
lambda). This is possible since here it is not a closure but will
be dynamically bound as a class method, and
avoid the creation of a new function for every decorated class.
The decorator return the class itself, after modification, and not a wrapped one, which is cleaner from the class metadata point of view (see discussion).
Since the instances dictionary is now added to each class, the class itself is no more used in the key, but
super is still used since the function is used to redefine the
__new__ method. For the same reason, the function
is explicitly defined as a class method. This is necessary since it is added to the class
after its creation, it would be unbounded if not marked as such.
Note that the decorator modify the class, and thus use side effects.
However, the class itself is returned. This is usually bad practice, but it is
required in the context of decorator, since the result of the decoration action
is the returned value. If the class were not returned,
(the variable) would result to be
None, the default return value for python
functions, and not the modified class, which would be inaccessible.
However, thanks to this side effect, one can modify an existing class by
flyweight on it without re-affecting the class name, as in
To be strict, calling the
flyweight function a
decorator is abusive, since it does not decorate the class in the
eponymous pattern sense, but modify it. This designation come from it’s use
@ syntax, and is usually admitted in the Python
An other way to add properties to a class without explicitly putting them in
its definition is to use a metaclass. A metaclass is the class that a
class is an instance of:
Class in Java,
python; that is the class that govern the creation of the class itself.
Contrary to Java, where
Class is final and there is no
(easy) way to specify an alternate metaclass for a class, this is quite easy in
python, by subtyping
type and using the
special class attribute (in Python < 3; for newer version, the metaclass is
specified using the
metaclass class parameter).
_get_instance method is an instance method of the
metaclass, it will be a class method of the flyweight class,
without decorating it with
@classmethod as in
the mixin version. If done, it would be a metaclass class method, that is
a method taking the metaclass as first argument.
initialise the created class, adding it the
and making its
__new__ method the same as its
_get_instance method, giving the same behaviour as the mixin
version, but without using inheritance. The
__init__ method works
exactly like the modifying decorator, but does not need to return the class,
since it’s a initialization method, working by side effect.
type.__init__ call is
a call to the super class of our metaclass, here
type, which is
the type for all python types, classes included. This call allow the proper
initialization of our instance, the flyweight class.
By affecting this flyweight metaclass to the
attribute of a class (e.g.
Spam), it became a
flyweight. The metaclass is automatically instantiated when the class
Functional Metaclass Version
Strictly speaking, from the python point of view, any callable returning a
class can be used as a metaclass, not only
type subclasses. Since
type can be called directly to create classes, creating such a
function is quite easy.
The parameters for
type are the class name, the class parents,
and a dictionary containing class properties (attributes and methods). These
parameters are automatically extracted from the class definition and provided
type function or to the
__metaclass__ callable when python
create the class.
Here, we create the class as defined, calling
type with the
unmodified parameters, and modify the result afterwards, adding the
__instances dictionary and the
__new__ method. This
approach is kind of an hybrid between the classical
metaclass and the modifying decorator.
Pure functional metaclass
An other way to create the class with the added features would be to modify
the last argument containing the class properties (here
__new__ before calling
type. The same variant can also be applied in the
This is the approach used in this last version, where the
__metaclass__ attribute is set to a function that create the class
type with modified arguments. Just to illustrate the
functional aspect, this function is defined as a
with the properties added in place. This version is just an illustration, and I
would not want to have to maintain it!
Concerning subclassing and introspection
If we need to subclass a flyweight class or use introspection on it, the wrapping approaches are not valid. Indeed, in these versions, we don’t have a direct access to the initial class, but to a function (or to the wrapping class) returning an instance. The class metadata (type, docstring, class name, super classes, and so on) are no more accessible. In the same way, we can’t directly use the decorated object as a superclass.
For introspection, some of the meta attributes can be copied to the
decorated object, whether manually or using facility functions from the
update_wrapper). However, not all properties or behaviours can be
copied in this way.
For subclassing, if the decorator is a class, as in the first
version, the class itself is accessible as the
_cls attribute, and
it is thus possible to subclass it, optionally redecorating it to also be a
flyweight. The process is however not elegant at all.
In the functional version, since the original class is hidden in the
closure, there is no way to subclass it.
If the flyweight classes need to be extended or analysed by introspection,
the modifying approaches are thus more suitable. The mixin approach works out of
the box, since we already deal with subclassing. The metaclass approach also
works fine, since the
__metaclass__ is inherited, and the
metaclass constructor is called at class creation, for the class or its
To be fully usable, the code snippets presented here should deal with
garbage collection, as discussed in the GoF (p. 200). Indeed, since the dictionary
in the flyweight factory keep
a reference to the created instance, it will never be collected, and the
__delete__) method will never be called, until the end
of the main program execution, which can be memory expensive or prevent some
behaviour to take place (e.g. synchronization on deletion).
If the desired behaviour of the flyweight is to be deleted, one can use
python weak references, from the
weakref module. As
stated in the weakref documentation,
a weak reference to an object is not enough to keep the object alive: when
the only remaining references to a referent are weak references, garbage
collection is free to destroy the referent and reuse its memory for
something else, which is exactly what is needed here.
module provides a
WeakValueDictionary object, behaving like a
dict, but storing only weak references to values. In the
previous code, replacing the instances dictionary by a
WeakValueDictionary would allow the garbage collector to destroy
the cached instance when no other object is using it.
We have considered two distinct methods:
- where the class is wrapped in an object providing the desired behaviour, like in the factory and the wrapping decorators;
- where the behaviours are added to the class:
From the final user point of view, considering code overweight, all approaches
are equivalents. Indeed, to make a class a flyweight, you just have to add a
metaclass, a parent mixin, or decorate the class (ignoring the two first
versions which just are a direct pattern implementation), and its use is
transparent (if using the versions that override
From the class metadata and subclassing point of view, modification is more suitable than delegation. Moreover, delegation creates a new object (instance or closure) for every flyweight class, whereas no overhead is introduced by the modification approaches.
However, delegation can be used with any callable object, whereas modification only applies to classes. It is therefore possible to use the decorator version to implement the memoize pattern, which keep the result of previous computations.
Finally, delegation and afterward modification are more flexible than inheritance or metaclass, which cannot be easily applied to existing classes.
The modifying decorator seems to be the more interesting approach in most of situations.