2016-09-17 3 views
3

J'ai une fonction et un décorateur de classe qui les transforme en singletons mais les docstrings sont en quelque sorte abandonnées. La fonction de transformation retourne un objet de classe qui a sa propre docstring qui devrait être écrasée. Comment puis-je contourner cela?Modification docstring par programme d'un objet de classe

def singleton(cls): 
    return cls() 

def singletonfunction(func): 
    return func() 

@singletonfunction 
def Bit(): 
    """A 1-bit BitField; must be enclosed in a BitStruct""" 
    return BitsInteger(1) 

Bit donne le Contrôle BitInteger docstring, pas celui de la fonction.

Répondre

1

laisse supposer la version originale est quelque chose comme ceci:

class BitsInteger: 
    """BitsInteger docstring""" 
    def __init__(self, num): 
     pass 

def singleton(cls): 
    return cls() 

def singletonfunction(func): 
    return func() 

@singletonfunction 
def Bit(): 
    """A 1-bit BitField; must be enclosed in a BitStruct""" 
    return BitsInteger(1) 

b = Bit 
print("b.__doc__ :", b.__doc__) 

L'exécution de ce avec Python3.5 donne la sortie:

b.__doc_ : BitsInteger docstring 

Cela pourrait ne pas être ce que vous attendez. Quand nous courons avec python -i original.py nous pouvons jeter un oeil autour de ce qui se passe vraiment ici:

>>> vars() 
{'__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, 'b': <__main__.BitsInteger object at 0x7ff05d2ae3c8>, '__spec__': None, 'singletonfunction': <function singletonfunction at 0x7ff05d2b40d0>, 'singleton': <function singleton at 0x7ff05d30cd08>, '__cached__': None, 'BitsInteger': <class '__main__.BitsInteger'>, '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7ff05d2eb4a8>, '__package__': None, 'Bit': <__main__.BitsInteger object at 0x7ff05d2ae3c8>, '__doc__': None} 
>>> 

Comme vous pouvez le voir b est en fait de type BitsInteger

La raison est parce que ce qui se passe réellement est que lorsque vous écrivez:

@singleton_function 
def Bit(): 
    """Bit docstring""" 
    ... 
    return BitsInteger(1) 

vous êtes vraiment juste de sucre syntaxique pour cela:

def Bit(): 
    """Bit docstring""" 
    ... 
    return BitsInteger(1) 
Bit = singleton_function(Bit) 

Dans ce cas Bit est la valeur de retour de singleton_function qui est en fait un BitsInteger. Je trouve que lorsque vous supprimez le sucre syntaxique, il est beaucoup plus clair ce qui se passe ici.

Si vous souhaitez avoir la commodité d'un décorateur qui ne change pas le docstring Je vous recommande d'utiliser wrapt

import wrapt 

class BitsInteger: 
    """BitsInteger docstring""" 
    def __init__(self, num): 
     pass 

def singleton(cls): 
    return cls() 

@wrapt.decorator 
def singletonfunction(func): 
    return func() 

@singletonfunction 
def Bit(): 
    """A 1-bit BitField; must be enclosed in a BitStruct""" 
    return BitsInteger(1) 

b = Bit 
print("b.__doc_ :", b.__doc__) 

Ce sorties:

b.__doc_ : A 1-bit BitField; must be enclosed in a BitStruct 

Maintenant, quand vous regardez Vars() vous voyez que 'b': <FunctionWrapper at 0x7f9a9ac42ba8 for function at 0x7f9a9a9e8c80> qui n'est plus un type BitInteger. Personnellement, j'aime utiliser wrapt parce que je reçois ce que je veux immédiatement. La mise en œuvre de cette fonctionnalité et la couverture de tous les cas de bord demande des efforts et je sais que cette fonctionnalité est bien testée et fonctionne comme prévu.

+0

Essentiellement 'Bit = BitInteger (1)'. Vous avez une faute de frappe dans la définition de Bit, il ne retourne pas une classe mais une instance. Pire, il ne semble pas fonctionner sur PY3 et il n'hérite pas des opérateurs/>>. – ArekBulski

+0

J'ai couru ceci avec cPython 3.5. Si vous pouviez mettre une partie de la définition de la classe 'BitsInteger' avec ce que vous devez obtenir dans la question, cela pourrait m'aider à améliorer la réponse ici. Je ne suis pas tout à fait clair sur ce que le problème original que vous essayez de résoudre est. Avez-vous besoin de 'Bit 'pour être appelable et de toujours retourner le même objet (singleton)? – shuttle87

+0

Bit devrait être une instance de classe, qui a la docstring prise de la fonction pas la classe. C'est tout. J'accepte votre solution, même si cela fonctionne parfois. – ArekBulski