简体   繁体   中英

Python decorated class documentation

I'm using a decorator for singletons in python, implemented as shown below.

I'd like to have the pydoc of the decorated class being exactly the same as the pydoc of the non decorated class, but I don't find how:

  • Without the getSingletonInstance.__doc__ = cls.__doc__ line, the pydoc of the decorated class gives the pydoc of the singleton function.

  • With the getSingletonInstance.__doc__ = cls.__doc__ line, the pydoc of the decorated class gives only the "top level" docstring.

How can I proceed?

Thanks.

def singleton(cls):
    """A singleton decorator

    Warnings
    --------
    Singleton gdecorated calsses cannot be inhehited

    Example
    -------
    >>> from decorators import singleton
    >>> @singleton
    ... class SingletonDemo():
    ...     pass
    >>> d1 = SingletonDemo()
    >>> d1.a = 0xCAFE
    >>> d2 = SingletonDemo()
    >>> id(d1) == id(d2)
    True
    >>> d1 == d2
    True
    >>> d2.a == 0xCAFE
    True

    References
    ----------
    See case 2 of https://www.python.org/dev/peps/pep-0318/#examples
    """
    _instances = {}

    def getSingletonInstance():
        if cls not in _instances:
            _instances[cls] = cls()
        return _instances[cls]

    getSingletonInstance.__doc__ = cls.__doc__

    return getSingletonInstance

Try using functools.wraps :

import functools

def wrapper(cls):
    _instances = {}
    class inner(cls):
        def __new__(subcls):
            if subcls not in _instances:
                _instances[subcls] = object.__new__(subcls)
            return _instances[subcls]
    inner.__doc__=cls.__doc__
    return inner

@wrapper
class A(object):
    """Example Docstring"""
    def method(self):
        """Method Docstring"

A.__doc__
# "Example Docstring"
A.method.__doc__
# "Method Docstring"

Answer summarizing all the discussions, with example. Thanks a lot to everybody.

This solution:

  • Preserves the docstring
  • Preserves the type
  • Supports static and class methods

Limitations:

  • Singletons cannot be inherited, which is meaningful regarding to the context

Solution: def singleton(cls):

    """A singleton decorator

    Warnings
    --------
    Singleton decorated classes cannot be inhehited

    Example
    -------
    >>> import abc
    >>> 
    >>> @singleton
    ... class A():
    ...     "Ad-hoc documentation of class A"
    ...     def __init__(self):
    ...         "Ad-hoc documentation of class A constructor"
    ...         print("constructor called")
    ...         self.x = None
    ...     @classmethod
    ...     def cm(cls):
    ...         "a class method"
    ...         print("class method called")
    ...     def im(self):
    ...         "an instance method"
    ...         print("instance method called")
    ...     @staticmethod
    ...     def sm():
    ...         "a static method"
    ...         print("static method called")
    ... 
    >>> @singleton
    ... class P(abc.ABCMeta):
    ...     @abc.abstractmethod
    ...     def __init__(self):
    ...         pass
    ... 
    >>> class C(P):
    ...     def __init__(self):
    ...         print("C1 constructor called")
    ... 
    >>> a1 = A()
    constructor called
    >>> a1.x = 0xCAFE
    >>> a1.x
    51966
    >>> a2 = A()
    >>> a2.x
    51966
    >>> a1.x == a2.x
    True
    >>> a1 == a2
    True
    >>> id(a1) == id(a2)
    True
    >>> type(a1) == type(a2)
    True
    >>> isinstance(a1, A)
    True
    >>> ta1 = type(a1)
    >>> issubclass(ta1, A)
    True
    >>> A.cm()
    class method called
    >>> a1.cm()
    class method called
    >>> A.sm()
    static method called
    >>> a1.sm()
    static method called
    >>> a1.im()
    instance method called
    >>> try:
    ...     C()
    ... except Exception as e:
    ...     type(e)
    ... 
    <class 'TypeError'>

    """
    _instances = {}
    _constructorCalled = []
    class inner(cls):
        def __new__(subcls):
            if subcls not in _instances:
                _instances[subcls] = cls.__new__(subcls)
            return _instances[subcls]
        def __init__(self):
            if type(self) not in _constructorCalled:
                cls.__init__(self)
                _constructorCalled.append(type(self))
        __init__.__doc__ = cls.__init__.__doc__
        __new__.__doc__ = cls.__new__.__doc__
        if __new__.__doc__ == (
            "Create and return a new object.  "
            "See help(type) for accurate signature."
        ):
            __new__.__doc__ = "Returns a singleton instance"
    inner.__doc__ = cls.__doc__
    return inner

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM