Metadata-Version: 1.0
Name: mementos
Version: 0.105
Summary: Memoizing metaclass. Drop-dead simple way to create cached objects
Home-page: UNKNOWN
Author: Jonathan Eunice
Author-email: jonathan.eunice@gmail.com
License: UNKNOWN
Description: Classes that use this caching metaclass will have their instances
        automatically cached based on instantiation-time arguments (i.e. to ``__init__``).
        Useful for not repetitively creating expensive-to-create objects,
        and for making sure that objects are created only once.
        
        Usage
        =====
        
        Say you have a class ``Thing`` that requires expensive computation to
        create, or that should be created only once. You can make that happen
        simply by adding one line to its definition::
        
            from mementos import MementoMetaclass
        
            class Thing(object):
                
                __metaclass__ = MementoMetaclass
                
                def __init__(self, name):
                    self.name = name
                
                ...
        
        Then ``Thing`` objects will be memoized::
        
            t1 = Thing("one")
            t2 = Thing("one")
            assert t1 is t2
            
        
        Notes
        =====
        
         *  Derived from `an ActiveState recipe
            <http://code.activestate.com/recipes/286132-memento-design-pattern-in-python/>`_ by Valentino Volonghi.
            
         *  It is safe to memoize multiple classes at the same time. They will all be stored in the same cache, but
            their class is a part of the cache key, so the values are distinct.
           
         *  This implementation is *not* thread-safe, in and of itself. If you're
            in a multi-threaded environment, wrap object instantiation in a lock.
           
         *  Be careful with call signatures. This metaclas
            caches on call signature, which can vary if keyword args
            are used. E.g. ``def func(a, b=2)`` could be called ``func(1)``, ``func(1,2)``,
            ``func(a=1)``, ``func(1, b=2)``, or ``func(a=2, b=2)``--and all resolve to the
            same logical call. And this is just for two parameters! If there are more
            than one kwarg, they can be arbitrarily ordered, creating *many* logically
            identical permuations. Thank Goodness Python doesn't allow kwargs to come
            before positional args, else there'd be even more ways to make the same
            call.
            
            So if you instantiate an object once, then again with a logically
            identical call but using a different calling structure/signature, the
            object won't be created and cached just once--it will be created and
            cached multiple times.::
            
                o1 = Thing("lovely")
                o2 = Thing(name="lovely")
                assert o1 is not o2   # because the call signature is different
                
            This may degrade performance, and can also create
            errors, if you're counting on ``mementos`` to create just one object.
            So don't do that. Use the same calling style, and it won't be a problem.
            
            In most cases, this isn't an issue, because objects tend to be
            instanitated with a limited number of parameters, and you can take care
            that you instantiate them with parallel call signatures. Since this works
            99% of the time and has a simple implementation, it's worth the price of
            this inelegance. For the 1% edge-cases where multiple call signature
            variations must be conclusively resolved to a unique canonical signature,
            the ``inspect`` module could be used (e.g. ``getargvalues()`` or
            ``getcallargs()`` to create such a unified key.
            
         *  Not to be confused with the `memento <http://pypi.python.org/pypi/memento>`_
            module, which does something completely different.
            
         *  In some cases, you may not want the entire initialization-time call signature
            to define the cache key--only part of it. (Because some arguments to ``__init__``
            may be useful, but not really part of the object's 'identity'.) The
            best option is to design ``__init__`` without superflous attributes, then
            create a second
            method that adds sets useful-but-not-essential data. E.g.::
        
                class OtherThing(object):
                        
                    __metaclass__ = MementoMetaclass
                    
                    def __init__(self, name):
                        self.name = name
                        self.color = None
                        self.weight = None
                        
                    def set(self, color=None, weight=None):
                        self.color = color or self.color
                        self.weight = weight or self.weight
                        return self
                
                ot1 = OtherThing("one").set(color='blue')
                ot2 = OtherThing("one").set(weight='light')
                assert ot1 is ot2
                assert ot1.color == ot2.color == 'blue'
                assert ot1.weight == ot2.weight == 'light'
        
        Installation
        ============
        
        ::
        
            pip install mementos
            
        (You may need to prefix this with "sudo " to authorize installation.)
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: BSD License
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
