Domanda

Python ci dà la possibilità di creare metodi e variabili 'privati' all'interno di una classe anteponendo doppi caratteri di sottolineatura al nome, in questo modo: __myPrivateMethod().Come si può allora spiegare questo?

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()
>>> obj.myPublicMethod()
public method
>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
>>> obj._MyClass__myPrivateMethod()
this is private!!

Qual è l'accordo?!

Lo spiegherò un po' per coloro che non hanno capito bene.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()

Quello che ho fatto è creare una classe con un metodo pubblico e un metodo privato e crearne un'istanza.

Successivamente, chiamo il suo metodo pubblico.

>>> obj.myPublicMethod()
public method

Successivamente, provo a chiamare il suo metodo privato.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

Tutto sembra a posto qui;non siamo in grado di chiamarlo.In effetti è "privato".Beh, in realtà non lo è.Corsa dir() sull'oggetto rivela un nuovo metodo magico che Python crea magicamente per tutti i tuoi metodi 'privati'.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

Il nome di questo nuovo metodo è sempre un carattere di sottolineatura, seguito dal nome della classe, seguito dal nome del metodo.

>>> obj._MyClass__myPrivateMethod()
this is private!!

Questo per quanto riguarda l'incapsulamento, eh?

In ogni caso, ho sempre sentito che Python non supporta l'incapsulamento, quindi perché provarci?Cosa dà?

È stato utile?

Soluzione

La codifica dei nomi viene utilizzata per garantire che le sottoclassi non sovrascrivano accidentalmente i metodi privati ​​e gli attributi delle rispettive superclassi.Non è progettato per impedire l'accesso intenzionale dall'esterno.

Per esempio:

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...     
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

Naturalmente il problema si interrompe se due classi diverse hanno lo stesso nome.

Altri suggerimenti

Esempio di funzione privata

import re
import inspect

class MyClass :

    def __init__(self) :
        pass

    def private_function ( self ) :
        try :
            function_call = inspect.stack()[1][4][0].strip()

            # See if the function_call has "self." in the begining
            matched = re.match( '^self\.', function_call )
            if not matched :
                print 'This is Private Function, Go Away'
                return
        except :
            print 'This is Private Function, Go Away'
            return

        # This is the real Function, only accessible inside class #
        print 'Hey, Welcome in to function'

    def public_function ( self ) :
        # i can call private function from inside the class
        self.private_function()

### End ###

Quando sono passato per la prima volta da Java a Python I odiato Questo.Mi ha spaventato a morte.

Oggi potrebbe essere proprio l’unica cosa amo di più su Python.

Adoro stare su una piattaforma dove le persone si fidano l'una dell'altra e non hanno la sensazione di dover costruire muri impenetrabili attorno al proprio codice.Nei linguaggi fortemente incapsulati, se un'API presenta un bug e hai capito cosa va storto, potresti comunque non essere in grado di aggirarlo perché il metodo necessario è privato.In Python l'atteggiamento è:"Sicuro".Se pensi di aver capito la situazione, magari l'hai anche letto, allora non possiamo che dirti "buona fortuna!".

Ricordate, l'incapsulamento non è nemmeno debolmente correlato alla "sicurezza", o al tenere i bambini lontani dal prato.È solo un altro modello che dovrebbe essere utilizzato per rendere una base di codice più semplice da comprendere.

Da http://www.faqs.org/docs/diveintopython/fileinfo_private.html

A rigor di termini, i metodi privati ​​sono accessibili al di fuori della loro classe, semplicemente non facilmente accessibili.Niente in Python è veramente privato;Internamente, i nomi dei metodi e degli attributi privati ​​sono maltrattati e sfrenati al volo per farli sembrare inaccessibili con i loro nomi dati.Puoi accedere al metodo __Parse della classe Mp3FileInfo con il nome _MP3FileInfo__Parse.Riconosci che questo è interessante, quindi promette di non farlo mai, mai nel codice reale.I metodi privati ​​sono privati ​​per un motivo, ma come molte altre cose a Python, la loro privatizza è in definitiva una questione di convenzione, non di forza.

La frase comunemente usata è "qui siamo tutti adulti consenzienti".Anteponendo un singolo carattere di sottolineatura (non esporre) o un doppio carattere di sottolineatura (nascondi), stai dicendo all'utente della tua classe che intendi che il membro sia "privato" in qualche modo.Tuttavia, hai fiducia che tutti gli altri si comportino in modo responsabile e lo rispettino, a meno che non abbiano una ragione convincente per non farlo (ad es.debugger, completamento del codice).

Se davvero devi avere qualcosa di privato, puoi implementarlo in un'estensione (ad es.in C per CPython).Nella maggior parte dei casi, tuttavia, impari semplicemente il modo Python di fare le cose.

Non è che tu non possa assolutamente aggirare la privacy dei membri in qualsiasi linguaggio (aritmetica dei puntatori in C++, riflessioni in .NET/Java).

Il punto è che ricevi un errore se provi a chiamare il metodo privato per sbaglio.Ma se vuoi darti la zappa sui piedi, fallo pure.

Modificare:Non provi a proteggere le tue cose tramite l'incapsulamento OO, vero?

IL class.__stuff la convenzione di denominazione consente al programmatore di sapere a cui non è destinato l'accesso __stuff da fuori.La storpiatura del nome rende improbabile che qualcuno lo faccia per sbaglio.

È vero, puoi ancora aggirare questo problema, è ancora più semplice che in altri linguaggi (che tra l'altro ti consentono anche di farlo), ma nessun programmatore Python lo farebbe se si preoccupa dell'incapsulamento.

Un comportamento simile esiste quando i nomi degli attributi del modulo iniziano con un singolo carattere di sottolineatura (ad es._foo).

Gli attributi del modulo denominati come tali non verranno copiati in un modulo di importazione quando si utilizza il file from* metodo, ad esempio:

from bar import *

Si tratta tuttavia di una convenzione e non di un vincolo linguistico.Questi non sono attributi privati;possono essere referenziati e manipolati da qualsiasi importatore.Alcuni sostengono che per questo motivo Python non può implementare un vero incapsulamento.

È solo una di quelle scelte di progettazione linguistica.Ad un certo livello sono giustificati.Fanno in modo che tu debba fare di tutto per provare a chiamare il metodo, e se ne hai davvero così tanto bisogno, devi avere una buona ragione!

Mi vengono in mente gli hook di debug e i test come possibili applicazioni, ovviamente utilizzate in modo responsabile.

Con Python 3.4 questo è il comportamento:

>>> class Foo:
        def __init__(self):
                pass
        def __privateMethod(self):
                return 3
        def invoke(self):
                return self.__privateMethod()


>>> help(Foo)
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  Methods defined here:
 |
 |  __init__(self)
 |
 |  invoke(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

 >>> f = Foo()
 >>> f.invoke()
 3
 >>> f.__privateMethod()
 Traceback (most recent call last):
   File "<pyshell#47>", line 1, in <module>
     f.__privateMethod()
 AttributeError: 'Foo' object has no attribute '__privateMethod'

https://docs.python.org/3/tutorial/classes.html#tut-private

Si noti che le regole di mutilazione sono progettate principalmente per evitare incidenti; è comunque possibile accedere o modificare una variabile considerata privata. Ciò può essere utile anche in circostanze speciali, come nel debugger.

Anche se la domanda è vecchia, spero che il mio snippet possa essere utile.

La preoccupazione più importante riguardo ai metodi e agli attributi privati ​​è dire agli sviluppatori di non chiamarli all'esterno della classe e questo è l'incapsulamento.si potrebbe fraintendere la sicurezza derivante dall'incapsulamento.quando si usa deliberatamente una sintassi come quella (sotto) che hai menzionato, non vuoi l'incapsulamento.

obj._MyClass__myPrivateMethod()

Sono migrato da C# e all'inizio è stato strano anche per me, ma dopo un po' sono arrivato all'idea che solo il modo in cui i progettisti di codice Python pensano all'OOP è diverso.

Perché i metodi "privati" di Python non sono effettivamente privati?

A quanto ho capito, loro non posso essere privato.Come potrebbe essere applicata la privacy?

La risposta ovvia è: "è possibile accedere ai membri privati ​​solo tramite self", ma non funzionerebbe - self non è speciale in Python, non è altro che un nome comunemente usato per il primo parametro di una funzione.

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