web-dev-qa-db-fra.com

Comment imprimer la Docstring de la fonction python depuis l'intérieur de la fonction elle-même?

Je veux imprimer la docstring d'une fonction python de l'intérieur de la fonction elle-même. Par exemple.

def my_function(self):
  """Doc string for my function."""
  # print the Docstring here.

Pour le moment, je fais cela directement après my_function a été défini.

print my_function.__doc__

Mais je préfère laisser la fonction le faire elle-même.

J'ai essayé d'appeler print self.__doc__print self.my_function.__doc__ et print this.__doc__ dans ma_fonction mais cela n'a pas fonctionné.

58
shane87
def my_func():
    """Docstring goes here."""
    print my_func.__doc__

Cela fonctionnera tant que vous ne modifiez pas l'objet lié au nom my_func.

new_func_name = my_func
my_func = None

new_func_name()
# doesn't print anything because my_func is None and None has no docstring

Les situations dans lesquelles vous feriez cela sont plutôt rares, mais elles se produisent.

Cependant, si vous écrivez un décorateur comme celui-ci:

def passmein(func):
    def wrapper(*args, **kwargs):
        return func(func, *args, **kwargs)
    return wrapper

Vous pouvez maintenant le faire:

@passmein
def my_func(me):
    print me.__doc__

Et cela garantira que votre fonction obtient une référence à elle-même (similaire à self) comme premier argument, afin qu'elle puisse toujours obtenir la docstring de la bonne fonction. S'il est utilisé sur une méthode, l'habituel self devient le deuxième argument.

65
kindall

Cela devrait fonctionner (dans mes tests, cela comprend également la sortie). Vous pourriez probablement utiliser __doc__ au lieu de getdoc, mais j'aime ça, c'est donc juste ce que j'ai utilisé. De plus, cela ne vous oblige pas à connaître les noms de la classe/méthode/fonction.

Exemples à la fois pour une classe, une méthode et une fonction. Dites-moi si ce n'est pas ce que vous cherchiez :)

from inspect import *

class MySelfExplaningClass:
    """This is my class document string"""

    def __init__(self):
        print getdoc(self)

    def my_selfexplaining_method(self):
        """This is my method document string"""
        print getdoc(getattr(self, getframeinfo(currentframe()).function))


explain = MySelfExplaningClass()

# Output: This is my class document string

explain.my_selfexplaining_method()

# Output: This is my method document string

def my_selfexplaining_function():
    """This is my function document string"""
    print getdoc(globals()[getframeinfo(currentframe()).function])

my_selfexplaining_function()

# Output: This is my function document string
8
Tehnix

Cela marche:

def my_function():
  """Docstring for my function"""
  #print the Docstring here.
  print my_function.__doc__

my_function()

dans Python 2.7.1

Cela fonctionne également:

class MyClass(object):
    def my_function(self):
        """Docstring for my function"""
        #print the Docstring here, either way works.
        print MyClass.my_function.__doc__
        print self.my_function.__doc__


foo = MyClass()

foo.my_function()

Cependant, cela ne fonctionnera pas seul:

class MyClass(object):
    def my_function(self):
        """Docstring for my function"""
        #print the Docstring here.
        print my_function.__doc__


foo = MyClass()

foo.my_function()

NameError: le nom global 'my_function' n'est pas défini

6
jgritty

Vous avez posé votre question comme une méthode de classe plutôt qu'une fonction. Les espaces de noms sont importants ici. Pour une fonction, print my_function.__doc__ est très bien, car ma_fonction est dans l'espace de noms global.

Pour une méthode de classe, alors print self.my_method.__doc__ serait la voie à suivre.

Si vous ne souhaitez pas spécifier le nom de la méthode, mais lui passez plutôt une variable, vous pouvez utiliser les fonctions intégrées hasattr (objet, attribut) et getattr (obj, attr), qui font ce qu'elles disent, vous permettant de passer des variables avec des chaînes étant le nom d'une méthode. par exemple.

class MyClass:
    def fn(self):
        """A docstring"""
        print self.fn.__doc__ 

def print_docstrings(object):
   for method in dir( object ):
       if method[:2] == '__':  # A protected function
           continue
       meth = getattr( object, method )
       if hasattr( meth , '__doc__' ):
           print getattr( meth , '__doc__' )

x = MyClass()
print_docstrings( x )
2
Alex Leach

Essayer:

class MyClass():
    # ...
    def my_function(self):
        """Docstring for my function"""
        print MyClass.my_function.__doc__
        # ...

(*) Il y avait deux points (:) Manquants après my_function()

1
juliomalegria

Comme indiqué plusieurs fois, l'utilisation du nom de la fonction est une recherche dynamique dans le répertoire globals (). Il ne fonctionne que dans le module de la définition et uniquement pour une fonction globale. Si vous voulez trouver la chaîne doc d'une fonction membre, vous devrez également rechercher le chemin à partir du nom de classe - ce qui est assez lourd car ces noms peuvent devenir assez longs:

def foo():
    """ this is foo """
    doc = foo.__doc__
class Foo:
    def bar(self):
       """ this is bar """
       doc = Foo.bar.__doc__

est équivalent à

def foo():
    """ this is foo """
    doc = globals()["foo"].__doc__
class Foo:
    def bar(self):
       """ this is bar """
       doc = globals()["Foo"].bar.__doc__

Si vous souhaitez rechercher la chaîne de doc de l'appelant, cela ne fonctionnera pas de toute façon car votre assistant d'impression peut vivre dans un module complètement différent avec un dictionnaire global () complètement différent. Le seul choix correct est de regarder dans le cadre de la pile - mais Python ne vous donne pas l'objet fonction en cours d'exécution, il n'a qu'une référence à l'objet code "f_code". Mais continuez, car il y a aussi une référence aux "f_globals" de cette fonction. Vous pouvez donc écrire une fonction pour obtenir le document de l'appelant comme ceci, et en variante, vous obtenez votre propre chaîne de document.

import inspect

def get_caller_doc():
    frame = inspect.currentframe().f_back.f_back
    for objref in frame.f_globals.values():
        if inspect.isfunction(objref):
            if objref.func_code == frame.f_code:
                return objref.__doc__
        Elif inspect.isclass(objref):
            for name, member in inspect.getmembers(objref):
                if inspect.ismethod(member):
                    if member.im_func.func_code == frame.f_code:
                        return member.__doc__

et allons le tester:

def print_doc():
   print get_caller_doc()

def foo():
   """ this is foo """
   print_doc()

class Foo:
    def bar(self):
       """ this is bar """
       print_doc()

def nothing():
    print_doc()

class Nothing:
    def nothing(self):
        print_doc()

foo()
Foo().bar()

nothing()
Nothing().nothing()

# and my doc

def get_my_doc():
    return get_caller_doc()

def print_my_doc():
    """ showing my doc """
    print get_my_doc()

print_my_doc()

entraîne cette sortie

 this is foo 
 this is bar 
None
None
 showing my doc 

En fait, la plupart des gens veulent que leur propre chaîne de documentation ne la transmette que comme argument, mais la fonction d'aide appelée peut la rechercher toute seule. J'utilise ceci dans mon code le plus unitaire, ce qui est parfois pratique pour remplir certains journaux ou pour utiliser la chaîne de doc comme données de test. C'est la raison pour laquelle le get_caller_doc () présenté ne recherche que les fonctions de test globales et les fonctions membres d'une classe de test, mais je suppose que cela suffit pour la plupart des gens qui veulent en savoir plus sur la chaîne de doc.

class FooTest(TestCase):
    def get_caller_doc(self):
        # as seen above
    def test_extra_stuff(self):
        """ testing extra stuff """
        self.createProject("A")
    def createProject(self, name):
        description = self.get_caller_doc()
        self.server.createProject(name, description)

Pour définir un get_frame_doc (frame) approprié avec sys._getframe (1) est laissé au lecteur ().

1
Guido U. Draheim

Il existe une méthode assez simple pour ce faire que personne n'a encore mentionnée:

import inspect

def func():
    """Doc string"""
    print inspect.getdoc(func)

Et cela fait ce que vous voulez.

Il n'y a rien d'extraordinaire ici. Tout ce qui se passe, c'est qu'en faisant func.__doc__ dans une fonction diffère la résolution d'attribut suffisamment longtemps pour avoir la recherche __doc__ ça marche comme prévu.

J'utilise ceci avec docopt pour les points d'entrée de script de console.

1
Keith Gaughan

insertion de print __doc__ juste après la déclaration de classe , avant le def __init__, affichera la chaîne de doc sur la console chaque fois que vous lancerez un objet avec la classe

0
emorphus