Classe "Private" (implementazione) in Python


107

Sto codificando un piccolo modulo Python composto da due parti:

  • alcune funzioni che definiscono un'interfaccia pubblica,
  • una classe di implementazione utilizzata dalle funzioni precedenti, ma che non è significativa al di fuori del modulo.

All'inizio, ho deciso di "nascondere" questa classe di implementazione definendola all'interno della funzione che la utilizza, ma questo ostacola la leggibilità e non può essere utilizzata se più funzioni riutilizzano la stessa classe.

Quindi, oltre ai commenti e alle docstring, esiste un meccanismo per contrassegnare una classe come "privata" o "interna"? Sono a conoscenza del meccanismo di sottolineatura, ma a quanto ho capito si applica solo alle variabili, alla funzione e al nome dei metodi.

Risposte:


175

Utilizza un unico prefisso di sottolineatura:

class _Internal:
    ...

Questa è la convenzione ufficiale di Python per i simboli "interni"; "from module import *" non importa oggetti con prefisso di sottolineatura.

Modifica: riferimento alla convenzione di sottolineatura singola


3
Non conoscevo la regola del carattere di sottolineatura estesa alle classi. Non voglio ingombrare il mio spazio dei nomi durante l'importazione, quindi questo comportamento è quello che stavo cercando. Grazie!
oparisy

1
Dal momento che affermi che questa è la convenzione "ufficiale" di Python, sarebbe carino con un collegamento. Un altro post qui dice che tutto è in modo ufficiale e si collega alla documentazione.
flodin

11
python.org/dev/peps/pep-0008 - _single_leading_underscore: debole indicatore di "uso interno". Ad esempio "from M import *" non importa gli oggetti il ​​cui nome inizia con un trattino basso. - Le lezioni per uso interno hanno una sottolineatura iniziale
Miglia

2
Un carattere di sottolineatura iniziale è la convenzione per contrassegnare le cose come interne, "non scherzare con questo", mentre tutto è più per i moduli progettati per essere usati con "importazione da M *", senza necessariamente implicare che gli utenti del modulo non dovrebbero toccare quella classe.
Miglia

65

In breve:

  1. Non puoi far rispettare la privacy . Non ci sono classi / metodi / funzioni private in Python. Almeno, non una privacy rigorosa come in altri linguaggi, come Java.

  2. Puoi solo indicare / suggerire privacy . Questo segue una convenzione. La convenzione di Python per contrassegnare una classe / funzione / metodo come privata è di farla precedere da un _ (trattino basso). Ad esempio, def _myfunc()o class _MyClass:. Puoi anche creare una pseudo-privacy anteponendo al metodo due trattini bassi (ad esempio:) __foo. Non è possibile accedere direttamente al metodo, ma è comunque possibile chiamarlo tramite un prefisso speciale utilizzando il nome della classe (ad esempio:) _classname__foo. Quindi il meglio che puoi fare è indicare / suggerire la privacy, non applicarla.

Python è come perl sotto questo aspetto. Parafrasando una famosa frase sulla privacy tratta dal libro Perl, la filosofia è che dovresti stare fuori dal soggiorno perché non sei stato invitato, non perché è difeso con un fucile.

Per maggiori informazioni:


In risposta al numero 1, puoi in qualche modo far rispettare la privacy dei metodi. L'uso di un doppio trattino basso come __method (self) lo renderà inaccessibile al di fuori della classe. Ma c'è un modo per aggirarlo chiamandolo come, Foo () ._ Foo__method (). Immagino che lo rinomina semplicemente in qualcosa di più esoterico.
Evan Fosmark

1
Quella citazione è accurata.
Paul Draper


10

Uno schema che a volte uso è questo:

Definisci una classe:

class x(object):
    def doThis(self):
        ...
    def doThat(self):
        ...

Crea un'istanza della classe, sovrascrivendo il nome della classe:

x = x()

Definisci i simboli che espongono la funzionalità:

doThis = x.doThis
doThat = x.doThat

Elimina l'istanza stessa:

del x

Ora hai un modulo che espone solo le tue funzioni pubbliche.


2
Mi ci è voluto un minuto per capire lo scopo / funzione di "sovrascrivere il nome della classe", ma ho avuto un grande sorriso quando l'ho fatto. Non sono sicuro di quando lo userò. :)
Zach Young

C'è un nome per questa tecnica?
Bishwas Mishra il


4

Per affrontare la questione delle convenzioni di progettazione, e come ha detto Christopher, non esiste davvero qualcosa come "privato" in Python. Questo può sembrare strano per qualcuno che proviene da un background C / C ++ (come me qualche tempo fa), ma alla fine, probabilmente ti renderai conto che seguire le convenzioni è abbastanza.

Vedere qualcosa con un carattere di sottolineatura davanti dovrebbe essere un buon suggerimento per non usarlo direttamente. Se sei preoccupato per l' help(MyClass)output disordinato (che è ciò che tutti guardano quando cercano come usare una classe), gli attributi / classi sottolineati non sono inclusi lì, quindi finirai per avere solo la tua interfaccia "pubblica" descritta.

Inoltre, avere tutto ciò che è pubblico ha i suoi fantastici vantaggi, come ad esempio, puoi testare praticamente qualsiasi cosa dall'esterno (cosa che non puoi fare con i costrutti privati ​​C / C ++).


4

Utilizza due caratteri di sottolineatura come prefisso ai nomi degli identificatori "privati". Per le classi in un modulo, utilizzare un singolo trattino basso iniziale e non verranno importate utilizzando "from module import *".

class _MyInternalClass:
    def __my_private_method:
        pass

(Non esiste un vero "privato" in Python. Per esempio, Python manipola automaticamente i nomi dei membri della classe con doppi trattini bassi per essere __clssname_mymember. Quindi, in realtà, se conosci il nome alterato puoi comunque usare l'entità "privato" . Vedi qui. E, naturalmente, è possibile scegliere di importare manualmente classi "interni" se si voleva).


Perché due _? Uno è sufficiente.
S.Lott

Un singolo trattino basso è sufficiente per impedire a "import" di importare classi e funzioni. Hai bisogno di due trattini bassi per indurre la funzione di alterazione del nome di Python. Avrebbe dovuto essere più chiaro; Ho modificato.
chroder

Ora, il follow-up. Perché il nome di mutilazione? Qual è il possibile vantaggio di ciò?
S.Lott

5
Il possibile vantaggio è infastidire altri sviluppatori che hanno bisogno di accedere a quelle variabili :)
Richard Levasseur
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.