Created
September 17, 2013 17:44
-
-
Save Wilfred/6597856 to your computer and use it in GitHub Desktop.
Ensure no class gets instantiated twice with the same arguments.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import copy | |
def make_hash(obj): | |
"""Make a hash from an arbitrary nested dictionary, list, tuple or | |
set. | |
""" | |
if isinstance(obj, set) or isinstance(obj, tuple) or isinstance(obj, list): | |
return hash(tuple([make_hash(e) for e in obj])) | |
elif not isinstance(obj, dict): | |
return hash(obj) | |
new_obj = copy.deepcopy(obj) | |
for k, v in new_obj.items(): | |
new_obj[k] = make_hash(v) | |
return hash(tuple(frozenset(new_obj.items()))) | |
class CacheInstancesMetaclass(type): | |
# Based on http://stackoverflow.com/a/5961102 | |
def __call__(cls, *args, **kwargs): | |
"""We can't just override __new__ on CacheInstances, because python | |
will call __init__ every time __new__ returns an instance, | |
even if we have already called __init__. | |
By using a metaclass we can override that behaviour. | |
""" | |
arg_hash = make_hash([args, kwargs]) | |
if arg_hash in cls.instantiated: | |
return cls.instantiated[arg_hash] | |
else: | |
# Call type and go through normal instantiation. | |
new_instance = type.__call__(cls, *args, **kwargs) | |
# Save the created instance and return it. | |
cls.instantiated[arg_hash] = new_instance | |
return new_instance | |
class CacheInstances(object): | |
"""A class that can only be instantiated once for each set of | |
arguments passed to __init__. | |
>>> class Foo(CacheInstances): pass | |
>>> f1 = Foo(x=1) | |
>>> f2 = Foo(x=1) | |
>>> f3 = Foo(x=2) | |
>>> f1 is f2 | |
True | |
>>> f2 is f3 | |
False | |
""" | |
__metaclass__ = CacheInstancesMetaclass | |
# Class attribute, shared between all instances. | |
instantiated = {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment