J'ai une fonction wrapper qui retourne une fonction. Existe-t-il un moyen de définir par programme la docstring de la fonction retournée? Si je pouvais écrire à __doc__
, je procéderais comme suit:
def wrapper(a):
def add_something(b):
return a + b
add_something.__doc__ = 'Adds ' + str(a) + ' to `b`'
return add_something
Alors je pourrais faire
>>> add_three = wrapper(3)
>>> add_three.__doc__
'Adds 3 to `b`
Cependant, puisque __doc__
est en lecture seule, je ne peux pas le faire. Quelle est la bonne façon?
Edit: Ok, je voulais garder cela simple, mais bien sûr, ce n’est pas ce que j’essaie de faire. Même si en général, __doc__
est inscriptible dans mon cas, ce n’est pas le cas.
J'essaie de créer des cas de test pour unittest
automatiquement. J'ai une fonction wrapper qui crée un objet de classe qui est une sous-classe de unittest.TestCase
:
import unittest
def makeTestCase(filename, my_func):
class ATest(unittest.TestCase):
def testSomething(self):
# Running test in here with data in filename and function my_func
data = loadmat(filename)
result = my_func(data)
self.assertTrue(result > 0)
return ATest
Si je crée cette classe et que je tente de définir la docstring de testSomething
, un message d'erreur s'affiche:
>>> def my_func(): pass
>>> MyTest = makeTestCase('some_filename', my_func)
>>> MyTest.testSomething.__doc__ = 'This should be my docstring'
AttributeError: attribute '__doc__' of 'instancemethod' objects is not writable
Je transmettrais la docstring à la fonction factory et utiliserais type
pour construire manuellement la classe.
def make_testcase(filename, myfunc, docstring):
def test_something(self):
data = loadmat(filename)
result = myfunc(data)
self.assertTrue(result > 0)
clsdict = {'test_something': test_something,
'__doc__': docstring}
return type('ATest', (unittest.TestCase,), clsdict)
MyTest = makeTestCase('some_filename', my_func, 'This is a docstring')
Un instancemethod
obtient sa docstring de son __func__
. Changez la docstring de __func__
à la place. (L'attribut __doc__
des fonctions est accessible en écriture.)
>>> class Foo(object):
... def bar(self):
... pass
...
>>> Foo.bar.__func__.__doc__ = "A super docstring"
>>> help(Foo.bar)
Help on method bar in module __main__:
bar(self) unbound __main__.Foo method
A super docstring
>>> foo = Foo()
>>> help(foo.bar)
Help on method bar in module __main__:
bar(self) method of __main__.Foo instance
A super docstring
De la 2.7 docs :
Méthodes définies par l'utilisateur
Un objet méthode défini par l'utilisateur combine une classe, une instance de classe (ou None) et tout objet appelable (Normalement une fonction définie par l'utilisateur).
Attributs spéciaux en lecture seule: im_self est l’objet instance de la classe, im_func est l’objet function ; im_class est la classe de im_self pour les méthodes liées ou la classe qui a demandé la méthode pour les méthodes non liées;
__doc__
est la documentation de la méthode (identique àim_func.__doc__
);__name__
est le nom de la méthode (identique àim_func.__name__
);__module__
est le nom du module dans lequel la méthode a été définie, ou None si non disponible.Modifié dans la version 2.2: im_self faisait référence à la classe qui a défini la méthode.
Modifié dans la version 2.6: Pour la compatibilité aval 3.0, im_func est également disponible sous la forme
__func__
, et im_self sous la forme__self__
.
Cela ajoute au fait que l'attribut __doc__
des classes de type type
ne peut pas être modifié. Le point intéressant est que cela n’est vrai que tant que la classe est créée en utilisant type. Dès que vous utilisez une métaclasse, vous pouvez simplement changer __doc__
.
L'exemple utilise le module abc (AbstractBaseClass). Il fonctionne avec une métaclasse ABCMeta
spéciale
import abc
class MyNewClass(object):
__metaclass__ = abc.ABCMeta
MyClass.__doc__ = "Changing the docstring works !"
help(MyNewClass)
aura pour résultat
"""
Help on class MyNewClass in module __main__:
class MyNewClass(__builtin__.object)
| Changing the docstring works !
"""
Je suppose que cela devrait être un commentaire, mais en rassemblant mes 50 premiers points ...
Il suffit d'utiliser des décorateurs. Voici votre cas:
def add_doc(value):
def _doc(func):
func.__doc__ = value
return func
return _doc
import unittest
def makeTestCase(filename, my_func):
class ATest(unittest.TestCase):
@add_doc('This should be my docstring')
def testSomething(self):
# Running test in here with data in filename and function my_func
data = loadmat(filename)
result = my_func(data)
self.assertTrue(result > 0)
return ATest
def my_func(): pass
MyTest = makeTestCase('some_filename', my_func)
print MyTest.testSomething.__doc__
> 'This should be my docstring'
Voici un cas d’utilisation similaire: Aide dynamique Python et génération de saisie semi-automatique
__doc__
n'est pas accessible en écriture uniquement lorsque votre objet est de type 'type'.
Dans votre cas, add_three
est une fonction et vous pouvez simplement définir __doc__
pour n’importe quelle chaîne.
Dans le cas où vous essayez de générer automatiquement des sous-classes unittest.TestCase, il se peut que plus de kilométrage remplace la méthode shortDescription .
C'est la méthode qui supprime la docstring sous-jacente jusqu'à la première ligne, comme dans la sortie unittest normale; ignorer cela était suffisant pour nous permettre de contrôler ce qui était indiqué dans des outils de reporting tels que TeamCity, ce dont nous avions besoin.