Source code for nti.externalization.singleton

# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False
# -*- coding: utf-8 -*-
"""
Support for fast, memory efficient singleton objects.

Why is this here? The externalization system can use lots of objects
as it goes through its process. Many of those objects are adapters
(for example, the decorator objectes), meaning a factory callable is
called to (create and) return an object (given a particular context,
and possibly request).

But the API of many adapter objects accept all the information they
need to have in the functions defined in the interface. That is, the
constructor does nothing useful with the context (and request). The
objects are stateless, and so constructing a new one for each adapter
invocation can be a waste of time and memory.

By either using the `SingletonMetaclass` as your metaclass, or
subclassing `Singleton`, that cost is paid only once, replacing a call
to a constructor and an object allocation with a faster call to return
a constant object.
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# This was originally based on code from sympy.core.singleton

__all__ = [
    'SingletonMetaclass',
    'Singleton',
]

[docs]class SingletonMetaclass(type): """ Metaclass for singleton classes most commonly used as external object decorators (adapters). These objects accept one or two context arguments to their ``__init__`` function, but they do not actually use them (because the same object is passed to their decoration method). Thus they can usefully be constructed just once and shared. This metaclass ensures the singleton property, ensures that the ``__init__`` method is a no-op, and ensures that the instance has no dictionary or instance variable. A singleton class has only one instance which is returned every time the class is instantiated. .. caution:: We cannot be used with :func:`six.with_metaclass` because it introduces temporary classes. You'll need to use the metaclass constructor directly:: AClass = SingletonMetaclass('AClass', (object,), {}) Alternatively, you can inherit from :class:`Singleton`. **Implementation Notes** The class is instantiated immediately at the point where it is defined by calling ``cls.__new__(cls)``. This instance is cached and ``cls.__new__`` is rebound to return it directly. The original constructor is also cached to allow subclasses to access it and have their own instance. >>> from nti.externalization.singleton import Singleton >>> class TopSingleton(Singleton): ... def __init__(self): ... print("I am never called") >>> inst = TopSingleton() >>> isinstance(inst, TopSingleton) True >>> TopSingleton() is inst True >>> class DerivedSingelton(TopSingleton): ... pass >>> derived = DerivedSingelton() >>> isinstance(derived, DerivedSingelton) True >>> DerivedSingelton() is derived True >>> derived is inst False """ def __new__(mcs, name, bases, cls_dict): # pylint:disable=bad-mcs-classmethod-argument cls_dict['__slots__'] = () # no ivars cls_dict['__init__'] = lambda *args: None cls = type.__new__(mcs, name, bases, cls_dict) ancestor = object for ancestor in cls.mro(): if '__new__' in ancestor.__dict__: break if isinstance(ancestor, SingletonMetaclass) and ancestor is not cls: ctor = ancestor._new_instance else: ctor = cls.__new__ cls._new_instance = staticmethod(ctor) the_instance = ctor(cls) cls.__new__ = staticmethod(lambda *args: the_instance) return cls
SingletonDecorator = SingletonMetaclass # BWC Singleton = SingletonMetaclass( 'Singleton', (object,), { '__doc__': "A base class for singletons. " "Can be more convenient than a metaclass for Python2/Python3 compatibility." } ) from nti.externalization._compat import import_c_accel import_c_accel(globals(), 'nti.externalization._singleton')