Hoe stel ik de docstring programmatisch in?

Ik heb een wrapper-functie die een functie retourneert. Is er een manier om de docstring van de geretourneerde functie programmatisch in te stellen? Als ik naar __doc__zou kunnen schrijven, zou ik het volgende doen:

def wrapper(a):
    def add_something(b):
       return a + b
    add_something.__doc__ = 'Adds ' + str(a) + ' to `b`'
    return add_something

Dan zou ik kunnen doen

>>> add_three = wrapper(3)
>>> add_three.__doc__
'Adds 3 to `b`

Omdat __doc__echter alleen-lezen is, kan ik dat niet doen. Wat is de juiste manier?


Bewerken: Ok, ik wilde het simpel houden, maar dit is natuurlijk niet wat ik probeer te doen. Ook al is __doc__over het algemeen beschrijfbaar, in mijn geval niet.

Ik probeer automatisch testcases te maken voor unittest. Ik heb een wrapper-functie die een klasseobject maakt dat een subklasse is van 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

Als ik deze klasse aanmaak en de docstring van testSomethingprobeer in te stellen, krijg ik een foutmelding:

>>> 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

Antwoord 1, autoriteit 100%

Een instancemethodhaalt zijn docstring uit zijn __func__. Wijzig in plaats daarvan de docstring van __func__. (Het __doc__attribuut van functies is beschrijfbaar.)

>>> 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

Van de 2.7 documenten:

Door de gebruiker gedefinieerde methoden

Een door de gebruiker gedefinieerd methodeobject combineert een klasse, een klasse-instantie (of Geen) en elke aanroepbare
object (normaal gesproken een door de gebruiker gedefinieerde functie).

Speciale alleen-lezen attributen: im_self is het instantieobject van de klasse, im_func is de functie
voorwerp; im_class is de klasse van im_self voor gebonden methoden of de klasse die om de . vroeg
methode voor ongebonden methoden; __doc__is de documentatie van de methode (zelfde als
im_func.__doc__);
__name__is de naam van de methode (hetzelfde als im_func.__name__);
__module__is de naam van de module waarin de methode is gedefinieerd, of Geen indien niet beschikbaar.

Gewijzigd in versie 2.2: im_self gebruikt om te verwijzen naar de klasse die de methode definieerde.

Gewijzigd in versie 2.6: voor 3.0 forward-compatibiliteit is im_func ook beschikbaar als
__func__,
en im_self als __self__.


Antwoord 2, autoriteit 38%

Ik zou de docstring doorgeven aan de fabrieksfunctie en typegebruiken om de klasse handmatig te construeren.

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')

Antwoord 3, autoriteit 20%

Dit is een aanvulling op het feit dat het __doc__attribuut van klassen van het type typeniet kan worden gewijzigd. Het interessante punt is dat dit alleen waar is zolang de klasse is gemaakt met behulp van type. Zodra je een metaclass gebruikt, kun je eigenlijk gewoon __doc__wijzigen.

Het voorbeeld gebruikt de abc (AbstractBaseClass) module. Het werkt met een speciale ABCMetametaclass

import abc
class MyNewClass(object):
    __metaclass__ = abc.ABCMeta
MyClass.__doc__ = "Changing the docstring works !"
help(MyNewClass)

zal resulteren in

"""
Help on class MyNewClass in module __main__:
class MyNewClass(__builtin__.object)
 |  Changing the docstring works !
"""

Antwoord 4, autoriteit 16%

Gebruik gewoon decorateurs. Dit is jouw geval:

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'

Hier is een vergelijkbare use-case: Dynamische hulp van Python en automatisch aanvullen


Antwoord 5, autoriteit 9%

__doc__is niet alleen beschrijfbaar als uw object van het type ‘type’ is.

In jouw geval is add_threeeen functie en kun je __doc__gewoon instellen op een willekeurige tekenreeks.


Antwoord 6

In het geval dat u automatisch unittest.TestCase-subklassen probeert te genereren, heeft u mogelijk meer kilometers die hun shortDescription-methode.

Dit is de methode die de onderliggende docstring stript tot op de eerste regel, zoals te zien is in normale unittest-uitvoer; het negeren ervan was voldoende om ons controle te geven over wat er werd weergegeven in rapportagetools zoals TeamCity, wat we nodig hadden.

Other episodes