2010-06-16 10 views
72

Sto scrivendo una classe leggera i cui attributi sono destinati ad essere accessibili pubblicamente e solo a volte sovrascritti in istanze specifiche. Non c'è alcuna disposizione nel linguaggio Python per la creazione di docstring per gli attributi di classe, o qualsiasi tipo di attributi, per quella materia. Qual è il modo accettato, se ce n'è uno, per documentare questi attributi? Attualmente sto facendo questo genere di cose:Come documentare gli attributi di classe in Python?

class Albatross(object): 
    """A bird with a flight speed exceeding that of an unladen swallow. 

    Attributes: 
    """ 

    flight_speed = 691 
    __doc__ += """ 
     flight_speed (691) 
      The maximum speed that such a bird can attain. 
    """ 

    nesting_grounds = "Raymond Luxury-Yacht" 
    __doc__ += """ 
     nesting_grounds ("Raymond Luxury-Yacht") 
      The locale where these birds congregate to reproduce. 
    """ 

    def __init__(self, **keyargs): 
     """Initialize the Albatross from the keyword arguments.""" 
     self.__dict__.update(keyargs) 

Questo si tradurrà in docstring della classe che contiene la parte iniziale standard di docstring, così come le linee aggiunte per ogni attributo tramite assegnazione aumentata per __doc__.

Anche se questo stile non sembra essere espressamente vietato nello docstring style guidelines, non è nemmeno menzionato come opzione. Il vantaggio qui è che fornisce un modo per documentare gli attributi insieme alle loro definizioni, mentre continua a creare una docstring di classe presentabile, evitando di dover scrivere commenti che reiterano le informazioni dalla docstring. Sono ancora un po 'infastidito dal fatto che devo scrivere due volte gli attributi; Sto considerando di utilizzare le rappresentazioni di stringa dei valori nella docstring per evitare almeno la duplicazione dei valori predefiniti.

Si tratta di una violazione atroce delle convenzioni della comunità ad hoc? Va bene? C'è un modo migliore? Ad esempio, è possibile creare un dizionario contenente valori e docstring per gli attributi e quindi aggiungere i contenuti alla classe __dict__ e docstring verso la fine della dichiarazione di classe; questo allevierebbe la necessità di digitare due volte i nomi e i valori degli attributi. edit: questa idea, secondo me, non è effettivamente possibile, almeno non senza costruire dinamicamente l'intera classe dai dati, il che sembra una pessima idea a meno che non ci sia qualche altra ragione per farlo.

Sono abbastanza nuovo per Python e sto ancora elaborando i dettagli dello stile di codifica, quindi anche le recensioni non correlate sono ben accette.

+0

Se si sta cercando un modo per documentare gli attributi del modello Django, questo potrebbe essere utile: https://djangosnippets.org/snippets/2533/ –

+0

Duplicato di [Come documentare campi e proprietà in Python?] (Http : //stackoverflow.com/questions/6060813/how-to-document-fields-and-properties-in-python) che contengono una soluzione diversa. – bufh

risposta

50

Per evitare confusione: il termine proprietà ha un specific meaning in python. Quello di cui stai parlando è ciò che chiamiamo class attributes. Dal momento che sono sempre messi in atto attraverso la loro classe, trovo che abbia senso documentarli all'interno della stringa doc della classe. Qualcosa di simile a questo:

class Albatross(object): 
    """A bird with a flight speed exceeding that of an unladen swallow. 

    Attributes: 
     flight_speed  The maximum speed that such a bird can attain. 
     nesting_grounds The locale where these birds congregate to reproduce. 
    """ 
    flight_speed = 691 
    nesting_grounds = "Throatwarbler Man Grove" 

penso che è molto facile per gli occhi rispetto all'approccio nel tuo esempio. Se volessi davvero una copia dei valori degli attributi per apparire nella stringa doc, li metterei accanto o sotto la descrizione di ciascun attributo.

Edit:

Tenete a mente che in Python, stringhe doc sono membri effettivi degli oggetti che documentano, non soltanto annotazioni di codice sorgente. Poiché le variabili di attributo di classe non sono oggetti stessi ma riferimenti a oggetti, non hanno modo di contenere stringhe doc proprie. Immagino che potresti creare un caso per le stringhe di documenti sui riferimenti, forse per descrivere "cosa dovrebbe andare qui" invece di "ciò che è effettivamente qui", ma trovo abbastanza facile farlo nella stringa doc della classe contenente.

+0

Suppongo che nella maggior parte dei casi questo va bene, dal momento che gli attributi -grazie per la correzione della terminologia- sono abbastanza sinteticamente dichiarati che possono essere semplicemente raggruppati all'inizio della dichiarazione di classe senza renderlo inattuabile per capovolgere avanti e indietro sia la documentazione che il valore predefinito} o {aggiorna entrambe le istanze della documentazione e/o il valore predefinito}. – intuited

+1

Si noti inoltre che il mio esempio farà apparire la documentazione per gli attributi nella docstring della classe. In realtà preferirei mettere la documentazione in docstrings degli attributi stessi, ma questo non funziona per la maggior parte dei tipi built-in. – intuited

+0

Sì, la mia idea iniziale era di dichiarare e.g. 'flight_speed = 691; flight_speed .__ doc__ = "blah blah" '. Penso che questo sia quello che stai citando nella tua ** modifica **. Sfortunatamente, questo non funziona per le istanze dei (più?) Tipi di builtin (come 'int' in quell'esempio).Funziona per le istanze di tipi definiti dall'utente. =========== C'era in realtà un PEP (scusate, dimentica il numero) che proponeva l'aggiunta di docstring per gli attributi di classe/modulo, ma è stato rifiutato perché non erano in grado di capire come renderlo chiaro se le docstring erano per gli attributi precedenti o seguenti. – intuited

18

si citi la PEP257: Convenzioni docstring, nella sezione What is a docstring si afferma:

letterali stringa che si verificano altrove nel codice Python possono agire anche come documentazione. Non sono riconosciuti dal compilatore bytecode Python e non sono accessibili come attributi dell'oggetto runtime (ad es.non assegnato a __doc__), ma due strumenti aggiuntivi possono essere estratti dagli strumenti software:

I valori letterali delle stringhe che si verificano immediatamente dopo un semplice assegnamento al livello superiore di un modulo, classe o metodo __init__ sono denominati "docstring degli attributi" .

E questo è spiegato in maggiori dettagli in PEP 258: docstring di attributi. Come spiegato sopra ʇsәɹoɈ. un attributo non è un oggetto che può possedere un __doc__ in modo che non vengano visualizzati in help() o pydoc. Queste docstring possono essere utilizzate solo per la documentazione generata.

Ma attualmente pochi strumenti li usano.

Il precedente Epydoc do use them e Sphinx l'hanno introdotto in v0.6 ed esteso in v1.1. Sfinge può usare docstring su una linea prima di un incarico o in un commento speciale dopo un incarico.

Vedere directive autoattribute in the Sphinx Manual e gli esempi di docstring di attributi lì.

+0

Il plugin jedi-vim riconosce anche le docstring degli attributi. –

+1

Non so quando questo è stato introdotto, ma Sphinx 1.2.2 sembra includere docstring di attributi nella documentazione generata. – jochen

+1

Grazie @jochen, aggiorno la mia risposta. – marcz

7

È possibile abusare delle proprietà per questo effetto. Le proprietà contengono un getter, un setter, un deleter, e una docstring. Ingenuamente, questo sarebbe ottenere molto verbose:

class C: 
    def __init__(self): 
     self._x = None 

    @property 
    def x(self): 
     """Docstring goes here.""" 
     return self._x 

    @x.setter 
    def x(self, value): 
     self._x = value 

    @x.deleter 
    def x(self): 
     del self._x 

allora si avrà un docstring appartenente al Cx:

In [24]: print(C.x.__doc__) 
Docstring goes here. 

di fare questo per molti attributi è ingombrante, ma si potrebbe immaginare una funzione di supporto myprop:

def myprop(x, doc): 
    def getx(self): 
     return getattr(self, '_' + x) 

    def setx(self, val): 
     setattr(self, '_' + x, val) 

    def delx(self): 
     delattr(self, '_' + x) 

    return property(getx, setx, delx, doc) 

class C: 
    a = myprop("a", "Hi, I'm A!") 
    b = myprop("b", "Hi, I'm B!") 

In [44]: c = C() 

In [46]: c.b = 42 

In [47]: c.b 
Out[47]: 42 

In [49]: print(C.b.__doc__) 
Hi, I'm B! 

Poi, chiamando Pythons interattive help darà:

Help on class C in module __main__: 

class C 
| Data descriptors defined here: 
| 
| a 
|  Hi, I'm A! 
| 
| b 
|  Hi, I'm B! 

which I think should be pretty much what you're after. 

Modifica: Mi rendo conto ora che possiamo forse evitare di passare il primo argomento a myprop perché il nome interno non ha importanza. Se le chiamate successive di myprop possono in qualche modo comunicare tra loro, potrebbero decidere automaticamente un nome di attributo interno lungo e improbabile. Sono sicuro che ci sono modi per implementarlo, ma non sono sicuro che ne valga la pena.