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é.
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.
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
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
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 )
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()
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 ().
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.
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