Domanda

Supponiamo che io abbia una classe con alcuni attributi. Come è meglio (nel senso di Pythonic-OOP) accedere a questi attributi? Proprio come obj.attr ? O forse scrivi get accessors? Quali sono gli stili di denominazione accettati per tali cose?

Modifica Puoi approfondire le migliori pratiche degli attributi di denominazione con un carattere di sottolineatura iniziale singolo o doppio? Vedo nella maggior parte dei moduli che viene utilizzato un singolo trattino basso.


Se questa domanda è già stata posta (e ho il sospetto che abbia, anche se la ricerca non ha prodotto risultati), ti preghiamo di indicarla - e la chiuderò.

È stato utile?

Soluzione

Il modo generalmente accettato di fare le cose è semplicemente usare attributi semplici, in questo modo

>>> class MyClass:
...     myAttribute = 0
... 
>>> c = MyClass()
>>> c.myAttribute 
0
>>> c.myAttribute = 1
>>> c.myAttribute
1

Se ti ritrovi a dover scrivere getter e setter, allora quello che vuoi cercare sono le proprietà della classe python " e l'articolo di Ryan Tomayko su Getters / Setters / Fuxors è un ottimo punto di partenza (anche se un po 'lungo)

Altri suggerimenti

Per quanto riguarda i caratteri di sottolineatura a singolo e doppio vantaggio: entrambi indicano lo stesso concetto di "riservatezza". Vale a dire, le persone conosceranno l'attributo (sia esso un metodo o un attributo di dati "normale" o qualsiasi altra cosa) non fa parte dell'API pubblica dell'oggetto. Le persone sapranno che toccarlo direttamente è invitare al disastro.

Inoltre, gli attributi di sottolineatura a doppio vantaggio (ma non gli attributi di sottolineatura a capo singolo) sono alterati dal nome per accedervi per caso da sottoclassi o in qualsiasi altro posto al di fuori della classe attuale meno probabile. Puoi ancora accedervi, ma non banalmente. Ad esempio:

>>> class ClassA:
...     def __init__(self):
...         self._single = "Single"
...         self.__double = "Double"
...     def getSingle(self):
...         return self._single
...     def getDouble(self):
...         return self.__double
... 
>>> class ClassB(ClassA):
...     def getSingle_B(self):
...         return self._single
...     def getDouble_B(self):
...         return self.__double
... 
>>> a = ClassA()
>>> b = ClassB()

Ora puoi accedere banalmente a a._single e b._single e ottenere l'attributo _single creato da ClassA :

>>> a._single, b._single
('Single', 'Single')
>>> a.getSingle(), b.getSingle(), b.getSingle_B()
('Single', 'Single', 'Single')

Ma il tentativo di accedere all'attributo __double sull'istanza a o b non funzionerà direttamente:

>>> a.__double
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: ClassA instance has no attribute '__double'
>>> b.__double
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: ClassB instance has no attribute '__double'

E sebbene i metodi definiti in ClassA possano accedervi direttamente (quando chiamati su entrambe le istanze):

>>> a.getDouble(), b.getDouble()
('Double', 'Double')

I metodi definiti in ClassB non possono:

>>> b.getDouble_B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in getDouble_B
AttributeError: ClassB instance has no attribute '_ClassB__double'

E proprio in quell'errore hai un indizio su cosa sta succedendo. Il nome dell'attributo __double , quando si accede all'interno di una classe, viene modificato in modo da includere il nome della classe a cui si accede in . Quando ClassA tenta di accedere a self .__ double , in realtà si trasforma - al momento della compilazione - in un accesso di self._ClassA__double , e allo stesso modo per ClassB . (Se un metodo in ClassB dovesse assegnare a __double , non incluso nel codice per brevità, non toccherebbe quindi ClassA codice> __ doppio ma crea un nuovo attributo.) Non esiste altra protezione di questo attributo, quindi puoi ancora accedervi direttamente se conosci il nome giusto:

>>> a._ClassA__double, b._ClassA__double
('Double', 'Double')

Quindi perché è un problema?

Bene, è un problema ogni volta che vuoi ereditare e cambiare il comportamento di qualsiasi codice che tratta questo attributo. Devi reimplementare tutto ciò che tocca direttamente questo attributo doppio trattino basso oppure devi indovinare il nome della classe e manipolarlo manualmente. Il problema peggiora quando questo attributo double-underscore è in realtà un metodo: sovrascrivere il metodo o chiamare il metodo in una sottoclasse significa eseguire manualmente la modifica del nome o reimplementare tutto il codice che chiama il metodo per non utilizzare il nome doppio trattino basso. Per non parlare dell'accesso all'attributo in modo dinamico, con getattr () : dovrai anche manipolarlo manualmente.

D'altra parte, poiché l'attributo è solo banalmente riscritto, offre solo una 'protezione' superficiale. Qualsiasi parte di codice può ancora ottenere l'attributo modificando manualmente, anche se ciò renderà il loro codice dipendente dal nome della tua classe e gli sforzi della tua parte per riformattare il tuo codificare o rinominare la classe (pur mantenendo lo stesso nome visibile dall'utente, una pratica comune in Python) infrange inutilmente il loro codice. Possono anche 'ingannare' Python nel fare loro il nome-mengling nominando la loro classe uguale alla tua: nota come non vi sia alcun nome di modulo incluso nel nome dell'attributo mangled. Infine, l'attributo double-underscore è ancora visibile in tutti gli elenchi di attributi e in tutte le forme di introspezione che non si occupano di saltare gli attributi a partire da un carattere di sottolineatura ( singolo ).

Quindi, se usi nomi con doppio trattino basso, li usi in modo estremamente parsimonioso, poiché possono risultare abbastanza scomodi e non li usano mai per i metodi o qualsiasi altra cosa una sottoclasse potrebbe mai desiderare reimplementare, sovrascrivere o accedere direttamente . E renditi conto che la doppia sottolineatura del nome principale non offre nessuna protezione reale . Alla fine, l'uso di un singolo trattino di sottolineatura principale ti vince tanto e ti dà meno dolore (potenziale, futuro). Utilizza un singolo trattino di sottolineatura iniziale.

  

Modifica: puoi approfondire le migliori pratiche degli attributi di denominazione con un carattere di sottolineatura iniziale singolo o doppio? Vedo nella maggior parte dei moduli che viene utilizzato un singolo trattino basso.

Il carattere di sottolineatura singolo non significa nulla di speciale per Python, è solo una buona pratica, dire a & he; probabilmente non vorrai accedervi a meno che tu non sappia cosa stai facendo " ;. Il doppio carattere di sottolineatura rende comunque il mangle Python il nome internamente rendendolo accessibile solo dalla classe in cui è definito.

Il doppio trattino di sottolineatura iniziale e finale indica una funzione speciale, come __add__ che viene chiamata quando si utilizza l'operatore +.

Ulteriori informazioni in PEP 8 , in particolare le " Convenzioni di denominazione " ; sezione.

Penso che la maggior parte acceda direttamente a loro, senza bisogno di metodi get / set.

>>> class myclass:
...     x = 'hello'
...
>>>
>>> class_inst = myclass()
>>> class_inst.x
'hello'
>>> class_inst.x = 'world'
>>> class_inst.x
'world'

A proposito, puoi usare la funzione dir () per vedere quali attributi / metodi sono collegati alla tua istanza:

>>> dir(class_inst)
['__doc__', '__module__', 'x']

Due barre inferiori principali, " __ " sono usati per rendere un attributo o una funzione privati. Per altre convenzioni fare riferimento a PEP 08: http://www.python.org/dev/peps/pep-0008/

Python non ha bisogno di definire gli accessi fin dall'inizio, poiché la conversione degli attributi in proprietà è rapida e indolore. Vedi quanto segue per una vivida dimostrazione:

Recovery from Addiction

Non ha senso fare getter / setter in Python, non puoi comunque proteggere roba e se hai bisogno di eseguire qualche codice extra quando ottieni / setta la proprietà guarda la proprietà () builtin (python -c ' help (proprietà) ')

Alcune persone usano getter e setter. A seconda dello stile di codifica che usi, puoi chiamarli getSpam e seteggs. Ma puoi anche renderti attributi in sola lettura o assegnare solo. È un po 'imbarazzante da fare. Un modo è quello di ignorare

> __getattr__

e

> __setattr__

metodi.

Modifica:

Mentre la mia risposta è ancora vera, non è giusta, come ho capito. Esistono modi migliori per creare accessori in Python e non sono molto imbarazzanti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top