I defined this singleton metaclass:
class Singleton(type):
"""Metaclass which implements the singleton pattern"""
_instances = {}
def __call__(self, *args, **kwargs):
if self not in self._instances:
self._instances[self] = super(Singleton, self).__call__(*args, **kwargs)
return self._instances[self]
Now, I want to test whether everything works OK. Here is what I've tried:
Singleton as metaclass) - their id() matchesid() matchescopy module and copied the first object with copy.copy() - their id() doesn't match nowI want to know why doesn't the copied object's id match with the original object. Since it's a Singleton, shouldn't the two objects have the same id?
The copy module does not create a new instance; instead it creates an empty class, and reassigns __class__ on that object to specifically avoid the __new__ or __init__ methods of the original.
You'll need to provide a custom __copy__ hook to return the instance unchanged instead:
class Singleton(type):
"""Metaclass which implements the singleton pattern"""
_instances = {}
def __call__(self, *args, **kwargs):
if self not in self._instances:
self._instances[self] = super(Singleton, self).__call__(*args, **kwargs)
return self._instances[self]
def __copy__(cls, instance):
return instance
copy looks up the __copy__ method directly on the class; it is instead found on the metaclass, looking up __copy__ on the class will return a bound method, and copy (expecting an unbound method) passes in the instance explicitly. This means that there will be two arguments passed in to __copy__; the first is the class (an instance of the metaclass), the second the instance of that class (self in traditional methods).
Unfortunately, __deepcopy__ is looked up on the instance instead, and the metaclass method is not found.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With