Questa domanda sembra venire regolarmente sia su StackOverflow che altrove, tuttavia non sono stato in grado di trovare una soluzione completamente soddisfacente.Python 3 - Metodo di ereditarietà di docstring senza rompere decoratori o violazione di DRY
Sembrano esserci due tipi di soluzioni comuni. La prima (ad esempio da http://article.gmane.org/gmane.comp.python.general/630549) utilizza una funzione decoratore:
class SuperClass:
def my_method(self):
'''Has a docstring'''
pass
class MyClass(SuperClass):
@copy_docstring_from(SuperClass)
def my_method(self):
pass
assert SuperClass.my_method.__doc__ == MyClass.my_method._doc__
Questo è probabilmente l'approccio più semplice, ma richiede di ripetere il nome della classe genitore, almeno una volta, e anche diventa molto più complicato se il docstring non può essere trovato nell'antenato diretto.
Il secondo approccio utilizza un metaclasse o classe di decoratore (cfr Inheriting methods' docstrings in Python, Inherit a parent class docstring as __doc__ attribute, http://mail.python.org/pipermail/python-list/2011-June/606043.html) e si presenta così:
class MyClass1(SuperClass, metaclass=MagicHappeningHere):
def method(self):
pass
# or
@frobnicate_docstrings
class MyClass2(SuperClass):
def method(self):
pass
assert SuperClass.my_method.__doc__ == MyClass1.my_method._doc__
assert SuperClass.my_method.__doc__ == MyClass2.my_method._doc__
Tuttavia, con questo approccio la docstring viene impostato solo dopo la creazione della classe e quindi non accessibile a decoratori, quindi il seguente non funzionerà:
def log_docstring(fn):
print('docstring for %s is %s' % (fn.__name__, fn.__doc__)
return fn
class MyClass(SuperClass, metaclass=MagicHappeningHere):
# or
#@frobnicate_docstrings
#class MyClass2(SuperClass):
@log_docstring
def method(self):
pass
Una terza idea interessante è stata discussa in Inherit docstrings in Python class inheritance. In questo caso, il decoratore di funzioni avvolge effettivamente il metodo e lo trasforma in un descrittore di metodo piuttosto che semplicemente aggiornando la sua docstring. Tuttavia, sembra che usare il martello per rompere un dado perché trasforma il metodo in un descrittore di metodo (che può avere anche implicazioni sulle prestazioni, sebbene io non abbia controllato), e inoltre non rende disponibile la docstring a nessun altro decoratore (e nell'esempio sopra li farà effettivamente crash perché il descrittore del metodo non ha attributo __name__
).
Esiste una soluzione che eviti tutti gli inconvenienti sopra citati, ovvero non richiede che io ripeta me stesso e assegni immediatamente la docstring utilizzando un decoratore?
Sono interessato a una soluzione per Python 3.
Ho implementato un po 'più intelligente di questo e alcuni esempi su http://code.activestate.com/recipes/578587-inherit-method-docstrings-without-breaking-decorat/ – Nikratio