Domanda

Vengo dal mondo Java e sto leggendo Python 3 Patterns, Recipes and Idioms di Bruce Eckels.

Durante la lettura delle classi, si continua dicendo che in Python non è necessario dichiarare le variabili di istanza. Li usi solo nel costruttore, e boom, sono lì.

Quindi, per esempio:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Se questo è vero, qualsiasi oggetto della classe Simple può semplicemente cambiare il valore della variabile s al di fuori della classe.

Ad esempio:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

In Java ci hanno insegnato le variabili pubbliche / private / protette. Queste parole chiave hanno senso perché a volte vuoi variabili in una classe a cui nessuno al di fuori della classe ha accesso.

Perché non è necessario in Python?

È stato utile?

Soluzione

È culturale. In Python, non scrivi nell'istanza o nelle variabili di classe di altre classi. In Java, nulla ti impedisce di fare lo stesso se davvero vuoi - dopotutto, puoi sempre modificare l'origine della classe stessa per ottenere lo stesso effetto. Python elimina questa pretesa di sicurezza e incoraggia i programmatori a essere responsabili. In pratica, funziona molto bene.

Se vuoi emulare variabili private per qualche motivo, puoi sempre usare il prefisso __ da PEP 8 . Python modifica i nomi di variabili come __foo in modo che non siano facilmente visibili al codice esterno alla classe che li contiene (anche se puoi aggirarlo se sei determinato abbastanza, proprio come puoi aggirare le protezioni di Java se ci lavori).

Per la stessa convenzione, il prefisso _ significa che stai lontano anche se tecnicamente non ti viene impedito di farlo . Non giochi con le variabili di un'altra classe che assomigliano a __foo o _bar .

Altri suggerimenti

Le variabili private in python sono più o meno un hack: l'interprete rinomina intenzionalmente la variabile.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

Ora, se provi ad accedere a __var al di fuori della definizione della classe, fallirà:

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

Ma puoi facilmente cavartela con questo:

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

Probabilmente sai che i metodi in OOP sono invocati in questo modo: x.printVar () = > A.printVar (x) , se A.printVar () può accedere ad alcuni campi in x , è possibile accedere a questo campo all'esterno A.printVar () ... dopo tutto, le funzioni sono create per la riusabilità, non vi è alcun potere speciale dato alle dichiarazioni all'interno.

Il gioco è diverso quando è coinvolto un compilatore ( la privacy è un concetto a livello di compilatore ). Conosce la definizione di classe con modificatori del controllo di accesso, quindi può sbagliare se le regole non vengono seguite al momento della compilazione

Come correttamente menzionato da molti dei commenti sopra, non dimentichiamo l'obiettivo principale dei modificatori di accesso: aiutare gli utenti di codice a capire cosa dovrebbe cambiare e cosa non dovrebbe. Quando vedi un campo privato, non ci si scherza. Quindi è principalmente lo zucchero sintattico che può essere facilmente raggiunto in Python da _ e __.

" In Java, ci è stato insegnato sulle variabili pubbliche / private / protette "

" Perché non è necessario in Python? "

Per lo stesso motivo, non è richiesto in Java.

Sei libero di usare o meno private e protetto .

Come programmatore Python e Java, ho scoperto che private e protetti sono concetti di design molto, molto importanti. Ma in pratica, in decine di migliaia di righe di Java e Python, non ho mai effettivamente usato private o protetto .

Perché no?

Ecco la mia domanda " protetta da chi? "

Altri programmatori nella mia squadra? Hanno la fonte. Che cosa significa protetto quando possono cambiarlo?

Altri programmatori su altri team? Lavorano per la stessa compagnia. Possono - con una telefonata - ottenere la fonte.

clienti? È una programmazione di lavoro a noleggio (in genere). I client (generalmente) possiedono il codice.

Quindi, da chi - precisamente - lo sto proteggendo?

Esiste una variazione di variabili private nella convenzione di sottolineatura.

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

Ci sono alcune sottili differenze, ma per motivi di programmazione il modello di purezza ideologica è abbastanza buono.

Ci sono esempi di decoratori @private che implementano più da vicino il concetto, ma YMMV. Probabilmente si potrebbe anche scrivere una definizione di classe che utilizza meta

Python ha un supporto limitato per identificatori privati, attraverso una funzione che antepone automaticamente il nome della classe a tutti gli identificatori che iniziano con due trattini bassi. Ciò è trasparente per il programmatore, per la maggior parte, ma l'effetto netto è che qualsiasi variabile denominata in questo modo può essere utilizzata come variabile privata.

Vedi qui per ulteriori informazioni al riguardo.

In generale, l'implementazione di Python dell'orientamento agli oggetti è un po 'primitiva rispetto ad altri linguaggi. Ma mi piace questo, in realtà. È un'implementazione molto concettualmente semplice e si adatta bene allo stile dinamico del linguaggio.

Come accennato in precedenza, è possibile indicare che una variabile o un metodo è privato anteponendolo a un carattere di sottolineatura. Se non ti sembra sufficiente, puoi sempre usare il decoratore property . Ecco un esempio:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

In questo modo, qualcuno o qualcosa che fa riferimento a bar sta effettivamente facendo riferimento al valore restituito della funzione bar anziché alla variabile stessa, e quindi è possibile accedervi ma non cambiato. Tuttavia, se qualcuno lo desiderasse davvero, potrebbe semplicemente usare _bar e assegnargli un nuovo valore. Non esiste un modo infallibile per impedire a qualcuno di accedere a variabili e metodi che si desidera nascondere, come è stato detto più volte. Tuttavia, l'utilizzo di property è il messaggio più chiaro che è possibile inviare per non modificare una variabile. property può essere utilizzato anche per percorsi di accesso getter / setter / deleter più complessi, come spiegato qui: https://docs.python.org/3/library/functions.html#property

L'unica volta che uso mai variabili private è quando devo fare altre cose quando scrivo o leggo dalla variabile e come tale devo forzare l'uso di un setter e / o getter.

Ancora una volta questo vale per la cultura, come già affermato. Ho lavorato a progetti in cui la lettura e la scrittura di variabili di altre classi era gratuita per tutti. Quando un'implementazione è diventata obsoleta, è stato necessario molto più tempo per identificare tutti i percorsi di codice che utilizzavano quella funzione. Quando è stato forzato l'uso di setter e getter, è possibile scrivere facilmente un'istruzione debug per identificare che il metodo obsoleto era stato chiamato e il percorso del codice che lo chiama.

Quando ti trovi in ??un progetto in cui chiunque può scrivere un'estensione, notificare agli utenti i metodi obsoleti che devono scomparire in alcune versioni, quindi è fondamentale per ridurre al minimo la rottura del modulo durante gli aggiornamenti.

Quindi la mia risposta è; se tu e i tuoi colleghi mantenete un semplice set di codici, non è sempre necessario proteggere le variabili di classe. Se stai scrivendo un sistema estensibile, diventa indispensabile quando vengono apportate modifiche al core che deve essere catturato da tutte le estensioni utilizzando il codice.

i concetti privati ??e protetti sono molto importanti. Ma python - solo uno strumento per la prototipazione e lo sviluppo rapido con risorse limitate disponibili per lo sviluppo, ecco perché alcuni dei livelli di protezione non sono così rigorosi seguiti in Python. Puoi utilizzare " __ " nel membro della classe, funziona correttamente, ma non sembra abbastanza buono - ogni accesso a tale campo contiene questi caratteri.

Inoltre, puoi notare che il concetto OOP in pitone non è perfetto, smaltalo o rubino molto più vicino al puro concetto OOP. Anche C # o Java sono più vicini.

Python è un ottimo strumento. Ma è un linguaggio OOP semplificato. Sintatticamente e concettualmente semplificato. L'obiettivo principale dell'esistenza di Python è offrire agli sviluppatori la possibilità di scrivere codice facilmente leggibile con un alto livello di astrazione in modo molto veloce.

Scusate ragazzi per " resurrecting " il thread, ma, spero che questo possa aiutare qualcuno:

In Python3 se vuoi solo " incapsulare " gli attributi di classe, come in Java, puoi semplicemente fare la stessa cosa in questo modo:

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Per creare un'istanza, procedi come segue:

ss = Simple("lol")
ss.show()

Nota che: print (ss .__ s) genererà un errore.

In pratica, Python3 offuscherà il nome dell'attributo globale. Trasformandolo come un "privato" attributo, come in Java. Il nome dell'attributo è ancora globale, ma in modo inaccessibile, come un attributo privato in altre lingue.

Ma non averne paura. Non importa Fa anche il lavoro. ;)

Python non ha variabili private come C ++ o Java. Se lo desideri, puoi accedere a qualsiasi variabile membro in qualsiasi momento. Tuttavia, non hai bisogno di variabili private in Python, perché in Python non è male esporre le variabili membro delle classi. Se hai la necessità di incapsulare una variabile membro, puoi farlo utilizzando " @ property " più tardi senza rompere il codice client esistente.

In Python il singolo trattino basso " _ " viene utilizzato per indicare che un metodo o una variabile non sono considerati come parte dell'API pubblico di una classe e che questa parte dell'API potrebbe cambiare tra versioni diverse. Puoi usare questi metodi / variabili, ma il tuo codice potrebbe rompersi, se usi una versione più recente di questa classe.

Il doppio trattino basso " __ " non significa una "variabile privata". Lo usi per definire variabili che sono " class local " e che non può essere facilmente ignorato dalle sottoclassi. Mangia il nome della variabile.

Ad esempio:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

self .__ Il nome di foobar viene automaticamente modificato in self._A__foobar in classe A. In classe B viene modificato in self._B__foobar. Quindi ogni sottoclasse può definire la propria variabile __foobar senza sovrascrivere le variabili dei genitori. Nulla ti impedisce di accedere alle variabili a partire da sottolineature doppie. Tuttavia, la modifica del nome ti impedisce di chiamare queste variabili / metodi per inciso.

Consiglio vivamente di guardare Raymond Hettingers parlare " Toolkit di sviluppo della classe Pythons " da Pycon 2013 (dovrebbe essere disponibile su Youtube), che fornisce un buon esempio del perché e come utilizzare le variabili @property e " __ " -stance.

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