Source code for monty.design_patterns

# coding: utf-8

from __future__ import absolute_import

from functools import wraps

__author__ = 'Shyue Ping Ong'
__copyright__ = 'Copyright 2014, The Materials Virtual Lab'
__version__ = '0.1'
__maintainer__ = 'Shyue Ping Ong'
__email__ = ''
__date__ = '1/24/14'

[docs]def singleton(cls): """ This decorator can be used to create a singleton out of a class. Usage:: @singleton class MySingleton(): def __init__(): pass """ instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance
[docs]def cached_class(klass): """ Decorator to cache class instances by constructor arguments. This results in a class that behaves like a singleton for each set of constructor arguments, ensuring efficiency. Note that this should be used for *immutable classes only*. Having a cached mutable class makes very little sense. For efficiency, avoid using this decorator for situations where there are many constructor arguments permutations. The keywords argument dictionary is converted to a tuple because dicts are mutable; keywords themselves are strings and so are always hashable, but if any arguments (keyword or positional) are non-hashable, that set of arguments is not cached. """ cache = {} @wraps(klass, assigned=("__name__", "__module__"), updated=()) class _decorated(klass): # The wraps decorator can't do this because __doc__ # isn't writable once the class is created __doc__ = klass.__doc__ def __new__(cls, *args, **kwargs): key = (cls,) + args + tuple(kwargs.items()) try: inst = cache.get(key, None) except TypeError: # Can't cache this set of arguments inst = key = None if inst is None: # Technically this is cheating, but it works, # and takes care of initializing the instance # (so we can override __init__ below safely); # calling up to klass.__new__ would be the # "official" way to create the instance, but # that raises DeprecationWarning if there are # args or kwargs and klass does not override # __new__ (which most classes don't), because # object.__new__ takes no parameters (and in # Python 3 the warning will become an error) inst = klass(*args, **kwargs) # This makes isinstance and issubclass work # properly inst.__class__ = cls if key is not None: cache[key] = inst return inst def __init__(self, *args, **kwargs): # This will be called every time __new__ is # called, so we skip initializing here and do # it only when the instance is created above pass return _decorated
[docs]class NullFile(object): """A file object that is associated to /dev/null.""" def __new__(cls): import os return open(os.devnull, 'w') def __init__(self): """no-op"""
[docs]class NullStream(object): """A fake stream with a no-op write.."""
[docs] def write(*args): """no-op"""