it-swarm-id.com

Mengapa metode 'pribadi' Python tidak benar-benar pribadi?

Python memberi kita kemampuan untuk membuat metode dan variabel 'privat' di dalam kelas dengan menambahkan ganda garis bawah pada nama, seperti ini: __myPrivateMethod(). Bagaimana, kemudian, seseorang dapat menjelaskan hal ini

>>> 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!!

Apa masalahnya ?!

Saya akan menjelaskan ini sedikit untuk mereka yang tidak mengerti.

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

Apa yang saya lakukan di sana adalah membuat kelas dengan metode publik dan metode pribadi dan instantiate.

Selanjutnya, saya sebut metode publiknya.

>>> obj.myPublicMethod()
public method

Selanjutnya, saya mencoba dan memanggil metode privatnya.

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

Semuanya terlihat bagus di sini; kami tidak dapat menyebutnya. Ini sebenarnya adalah 'pribadi'. Sebenarnya tidak. Menjalankan dir () pada objek tersebut mengungkapkan metode magis baru yang python buat secara ajaib untuk semua metode 'pribadi' Anda.

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

Nama metode baru ini selalu garis bawah, diikuti oleh nama kelas, diikuti oleh nama metode.

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

Begitu banyak untuk enkapsulasi, eh?

Bagaimanapun, saya selalu mendengar Python tidak mendukung enkapsulasi, jadi mengapa bahkan mencoba? Apa yang menyebabkannya?

557
willurd

Perebutan nama digunakan untuk memastikan bahwa subclass tidak sengaja menimpa metode pribadi dan atribut superclasses mereka. Itu tidak dirancang untuk mencegah akses yang disengaja dari luar.

Sebagai contoh:

>>> 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}

Tentu saja, itu rusak jika dua kelas berbeda memiliki nama yang sama.

524
Alya

Contoh fungsi pribadi

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 ###
206
arun

Ketika saya pertama kali datang dari Jawa ke Python I benci ini. Itu membuatku takut sampai mati.

Hari ini mungkin hanya satu hal Saya paling suka tentang Python.

Saya suka berada di platform, di mana orang saling mempercayai dan tidak merasa perlu membangun tembok yang tidak bisa ditembus di sekitar kode mereka. Dalam bahasa yang dienkapsulasi dengan kuat, jika API memiliki bug, dan Anda telah menemukan apa yang salah, Anda mungkin masih tidak dapat mengatasinya karena metode yang diperlukan bersifat pribadi. Dalam Python sikapnya adalah: "yakin". Jika Anda pikir Anda memahami situasinya, mungkin Anda bahkan sudah membacanya, maka yang bisa kita katakan adalah "semoga sukses!".

Ingat, enkapsulasi bahkan tidak berhubungan lemah dengan "keamanan", atau menjauhkan anak-anak dari halaman. Ini hanyalah pola lain yang harus digunakan untuk membuat basis kode lebih mudah dipahami.

141
Thomas Ahle

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

Sebenarnya, metode pribadi adalah dapat diakses di luar kelas mereka, cukup tidak mudah diakses. Tidak ada dalam Python benar-benar pribadi; secara internal, nama metode pribadi dan atribut hancur dan tidak berubah dengan cepat untuk membuatnya tampak tidak dapat diakses dengan nama yang diberikan. Kamu dapat mengakses metode __parse dari Kelas MP3FileInfo dengan nama _MP3FileInfo__parse. Akui bahwa ini menarik, lalu berjanji pada tidak pernah, pernah melakukannya dalam kode nyata . Metode pribadi bersifat pribadi untuk alasan, tetapi seperti banyak hal lain dalam Python, privasi mereka adalah pada akhirnya masalah konvensi, bukan memaksa.

134
xsl

Ungkapan yang umum digunakan adalah "kita semua menyetujui orang dewasa di sini". Dengan memprioritaskan satu garis bawah (jangan tampilkan) atau garis bawah dua (menyembunyikan), Anda memberi tahu pengguna kelas Anda bahwa Anda bermaksud anggota untuk menjadi 'pribadi' dengan cara tertentu. Namun, Anda memercayai semua orang untuk berperilaku secara bertanggung jawab dan menghargai itu, kecuali mereka memiliki alasan kuat untuk tidak (mis. Pengingkar, penyelesaian kode).

Jika Anda benar-benar harus memiliki sesuatu yang bersifat pribadi, maka Anda dapat menerapkannya dalam ekstensi (mis. Dalam C untuk CPython). Namun, dalam kebanyakan kasus, Anda hanya mempelajari cara Pythonic dalam melakukan sesuatu.

86
Tony Meyer

Ini tidak seperti Anda absolutly dan tidak dapat menyiasati privasi anggota dalam bahasa apa pun (penunjuk aritmatika dalam C++, Refleksi dalam .NET/Java).

Intinya adalah Anda mendapatkan kesalahan jika Anda mencoba memanggil metode pribadi secara tidak sengaja. Tetapi jika Anda ingin menembak diri sendiri, silakan dan lakukan.

Sunting: Anda tidak mencoba mengamankan barang-barang Anda dengan OO-enkapsulasi, bukan?

32
Maximilian

Perilaku serupa ada ketika nama atribut modul dimulai dengan garis bawah tunggal (mis. _Foo).

Atribut modul yang namanya tidak akan disalin ke modul impor saat menggunakan metode from*, mis .:

from bar import *

Namun, ini adalah konvensi dan bukan kendala bahasa. Ini bukan atribut pribadi; mereka dapat dirujuk dan dimanipulasi oleh importir mana pun. Beberapa berpendapat bahwa karena ini, Python tidak dapat mengimplementasikan enkapsulasi yang benar.

12
Ross

Itu hanya salah satu dari pilihan desain bahasa itu. Pada tingkat tertentu mereka dibenarkan. Mereka membuatnya sehingga Anda harus pergi jauh dari cara Anda untuk mencoba dan memanggil metode, dan jika Anda benar-benar membutuhkannya, Anda harus memiliki alasan yang cukup bagus!

Kait debugging dan pengujian muncul dalam pikiran sebagai aplikasi yang mungkin, tentu saja digunakan secara bertanggung jawab.

12
ctcherry

Konvensi penamaan class.__stuff memberi tahu programmer bahwa ia tidak dimaksudkan untuk mengakses __stuff dari luar. Nama mangling membuatnya tidak mungkin ada orang yang melakukannya secara tidak sengaja.

Benar, Anda masih bisa mengatasi ini, bahkan lebih mudah daripada dalam bahasa lain (yang BTW juga membiarkan Anda melakukan ini), tetapi tidak ada programmer Python yang akan melakukan ini jika dia peduli tentang enkapsulasi.

11
Nickolay

Dengan Python 3.4 ini adalah perilaku:

>>> 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

Perhatikan bahwa aturan mangling sebagian besar dirancang untuk menghindari kecelakaan; masih dimungkinkan untuk mengakses atau memodifikasi variabel yang dianggap pribadi. Ini bahkan bisa berguna dalam keadaan khusus, seperti di debugger.

Meskipun pertanyaannya sudah tua, saya harap cuplikan saya dapat membantu.

3
Alberto

Kekhawatiran yang paling penting tentang metode dan atribut pribadi adalah memberi tahu pengembang untuk tidak menyebutnya di luar kelas dan ini enkapsulasi. orang mungkin salah memahami keamanan dari enkapsulasi. ketika seseorang dengan sengaja menggunakan sintaks seperti itu (di bawah) yang Anda sebutkan, Anda tidak ingin enkapsulasi.

obj._MyClass__myPrivateMethod()

Saya telah bermigrasi dari C # dan pada awalnya itu aneh bagi saya juga, tetapi setelah beberapa saat saya sampai pada gagasan bahwa hanya cara yang dipikirkan oleh perancang kode Python tentang OOP berbeda. 

2
Afshin Amiri

Mengapa metode 'pribadi' Python tidak benar-benar pribadi?

Seperti yang saya pahami, mereka tidak bisa menjadi pribadi. Bagaimana privasi bisa ditegakkan?

Jawaban yang jelas adalah "anggota pribadi hanya dapat diakses melalui self", tetapi itu tidak akan berfungsi - self tidak istimewa dalam Python, itu tidak lebih dari nama yang umum digunakan untuk parameter pertama dari suatu fungsi.

0
user200783