Dapatkah seseorang tolong jelaskan arti sebenarnya dari memiliki garis bawah di depan nama objek dengan Python, dan perbedaan antara keduanya?
Juga, apakah makna itu tetap sama apakah objek yang dimaksud adalah variabel, fungsi, metode, dll.?
Dapatkah seseorang tolong jelaskan arti sebenarnya dari memiliki garis bawah di depan nama objek dengan Python, dan perbedaan antara keduanya?
Juga, apakah makna itu tetap sama apakah objek yang dimaksud adalah variabel, fungsi, metode, dll.?
Jawaban:
Nama-nama, di kelas, dengan garis bawah utama hanya untuk menunjukkan kepada programmer lain bahwa atribut atau metode dimaksudkan untuk bersifat pribadi. Namun, tidak ada yang istimewa dilakukan dengan nama itu sendiri.
Mengutip PEP-8 :
_single_leading_underscore: indikator "penggunaan internal" lemah. Misalnya
from M import *
tidak mengimpor objek yang namanya dimulai dengan garis bawah.
Dari dokumen Python :
Setiap pengidentifikasi formulir
__spam
(setidaknya dua garis bawah utama, paling banyak satu garis bawah garis bawah) diganti secara teks_classname__spam
, di manaclassname
nama kelas saat ini dengan garis bawah utama bergaris-garis. Mangling ini dilakukan tanpa memperhatikan posisi sintaksis pengidentifikasi, sehingga dapat digunakan untuk mendefinisikan instance kelas-privat dan variabel kelas, metode, variabel yang disimpan dalam global, dan bahkan variabel yang disimpan dalam instance. pribadi ke kelas ini pada instance dari kelas lain.
Dan peringatan dari halaman yang sama:
Name mangling dimaksudkan untuk memberi kelas cara yang mudah untuk mendefinisikan variabel instance dan metode "private", tanpa harus khawatir tentang variabel instan yang ditentukan oleh kelas turunan, atau mengaitkan variabel instan dengan kode di luar kelas. Perhatikan bahwa aturan mangling sebagian besar dirancang untuk menghindari kecelakaan; masih mungkin bagi jiwa yang ditentukan untuk mengakses atau memodifikasi variabel yang dianggap pribadi.
>>> class MyClass():
... def __init__(self):
... self.__superprivate = "Hello"
... self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
__
menggandakan garis bawah sebagai nama variabel? sepertia, __ = foo()
Jawaban yang sangat bagus sejauh ini tetapi beberapa berita hilang. Satu garis bawah utama tidak persis hanya sebuah konvensi: jika Anda menggunakan from foobar import *
, dan modul foobar
tidak mendefinisikan __all__
daftar, nama yang diimpor dari modul tidak termasuk yang dengan garis bawah utama. Katakanlah itu sebagian besar adalah konvensi, karena kasus ini adalah sudut yang cukup tidak jelas ;-).
Konvensi terkemuka-garis bawah secara luas digunakan tidak hanya untuk pribadi nama, tetapi juga untuk apa C ++ sebut dilindungi yang - misalnya, nama-nama metode yang sepenuhnya dimaksudkan untuk menjadi ditimpa oleh subclass (bahkan yang harus menjadi ditimpa karena dalam kelas dasar mereka raise NotImplementedError
! -) seringkali merupakan nama tunggal dengan garis bawah yang menunjukkan kode menggunakan instance kelas tersebut (atau subclass) yang mengatakan metode tidak dimaksudkan untuk dipanggil secara langsung.
Sebagai contoh, untuk membuat antrian thread-safe dengan disiplin antrian yang berbeda dari FIFO, seseorang mengimpor Antrian, subkelas Antrian. Antrian, dan mengganti metode seperti _get
dan _put
; "kode klien" tidak pernah memanggil metode ("pengait") itu, melainkan metode publik ("pengorganisasian") seperti put
dan get
(ini dikenal sebagai pola desain Metode Templat - lihat misalnya di sini untuk presentasi menarik berdasarkan video dari pembicaraan saya tentang masalah ini, dengan penambahan sinopsis transkrip).
Sunting: Tautan video dalam uraian pembicaraan sekarang terputus. Anda dapat menemukan dua video pertama di sini dan di sini .
_var_name
atau menggunakan var_name
+ tidak termasuk dari __all__
?
__all__
kapan pun Anda ingin membuat modul ini from spam import *
ramah (termasuk di penerjemah interaktif). Jadi sebagian besar waktu, jawabannya adalah keduanya .
_
pribadi . Jelas saya berbicara tentang analogi, karena tidak ada yang benar-benar pribadi di Python. Ketika menyelam ke semantik saya akan mengatakan kita dapat mengikat _
ke Jawa dilindungi karena diproklamasikan di Jawa berarti "kelas turunan dan / atau dalam paket yang sama". Ganti paket dengan modul karena PEP8 sudah memberi tahu kami bahwa _
itu bukan hanya sebuah konvensi ketika berbicara tentang *
impor dan Anda memilikinya. Dan pastinya __
akan setara dengan private Java ketika berbicara tentang pengidentifikasi dalam suatu kelas.
__foo__
: ini hanya sebuah konvensi, cara bagi sistem Python untuk menggunakan nama yang tidak akan bertentangan dengan nama pengguna.
_foo
: ini hanya sebuah konvensi, cara bagi pemrogram untuk menunjukkan bahwa variabel bersifat pribadi (apa pun artinya dengan Python).
__foo
: ini memiliki arti nyata: interpreter menggantikan nama ini dengan _classname__foo
cara untuk memastikan bahwa nama tersebut tidak akan tumpang tindih dengan nama yang serupa di kelas lain.
Tidak ada bentuk garis bawah lainnya yang memiliki makna di dunia Python.
Tidak ada perbedaan antara kelas, variabel, global, dll dalam konvensi ini.
__foo
dan ingin tahu. Bagaimana bisa tumpang tindih dengan nama metode yang sama dengan Kelas lainnya? Maksud saya Anda masih harus mengaksesnya seperti instance.__foo()
(jika tidak diubah namanya oleh penerjemah), bukan?
from module import *
tidak mengimpor objek underscore-prefixed. Karena itu, _foo
lebih dari sekedar konvensi.
B
subclass kelas A
, dan keduanya mengimplementasikan foo()
, maka B.foo()
menimpa yang .foo()
diwarisi dari A
. Sebuah instance dari B
hanya akan dapat mengakses B.foo()
, kecuali melalui super(B).foo()
.
__dunder__
nama, pemanggilan implisit melewati kamus instance, jadi itu mungkin sedikit lebih dari sekadar konvensi penamaan dalam beberapa kasus (lihat bagian metode pencarian khusus dalam model data).
._variable
semiprivate dan dimaksudkan hanya untuk konvensi
.__variable
sering dianggap salah superprivat, sementara itu arti sebenarnya hanya untuk namemangle untuk mencegah akses tidak disengaja [1]
.__variable__
biasanya dicadangkan untuk metode atau variabel bawaan
Anda masih dapat mengakses .__mangled
variabel jika Anda sangat ingin. Double menggarisbawahi hanya namemangles, atau mengubah nama, variabel menjadi sepertiinstance._className__mangled
Contoh:
class Test(object):
def __init__(self):
self.__a = 'a'
self._b = 'b'
>>> t = Test()
>>> t._b
'b'
t._b dapat diakses karena hanya disembunyikan oleh konvensi
>>> t.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
t .__ a tidak ditemukan karena tidak ada lagi karena penamaan
>>> t._Test__a
'a'
Dengan mengakses instance._className__variable
alih-alih hanya nama garis bawah ganda, Anda dapat mengakses nilai tersembunyi
Garis bawah tunggal di awal:
Python tidak memiliki metode pribadi yang nyata. Sebaliknya, satu garis bawah pada awal metode atau nama atribut berarti Anda tidak boleh mengakses metode ini, karena itu bukan bagian dari API.
class BaseForm(StrAndUnicode):
def _get_errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
errors = property(_get_errors)
(Potongan kode ini diambil dari kode sumber Django: Django / form / forms.py). Dalam kode ini,errors
adalah properti publik, tetapi metode yang dipanggil oleh properti ini, _get_errors, adalah "pribadi", jadi Anda tidak boleh mengaksesnya.
Dua garis bawah di awal:
Ini menyebabkan banyak kebingungan. Seharusnya tidak digunakan untuk membuat metode pribadi. Ini harus digunakan untuk menghindari metode Anda ditimpa oleh subclass atau diakses secara tidak sengaja. Mari kita lihat sebuah contoh:
class A(object):
def __test(self):
print "I'm a test method in class A"
def test(self):
self.__test()
a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!
Keluaran:
$ python test.py
I'm test method in class A
I'm test method in class A
Sekarang buat subclass B dan lakukan kustomisasi untuk metode __test
class B(A):
def __test(self):
print "I'm test method in class B"
b = B()
b.test()
Output akan ....
$ python test.py
I'm test method in class A
Seperti yang telah kita lihat, A.test () tidak memanggil metode B .__ test (), seperti yang kita harapkan. Tetapi pada kenyataannya, ini adalah perilaku yang benar untuk __. Dua metode yang disebut __test () secara otomatis diganti namanya (mangled) menjadi _A__test () dan _B__test (), sehingga mereka tidak sengaja menimpa. Ketika Anda membuat metode dimulai dengan __ itu berarti Anda tidak ingin siapa pun dapat menimpanya, dan Anda hanya bermaksud mengaksesnya dari dalam kelasnya sendiri.
Dua garis bawah di awal dan di akhir:
Ketika kita melihat metode seperti __this__
, jangan menyebutnya. Ini adalah metode yang dimaksudkan untuk memanggil python, bukan Anda. Mari lihat:
>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11
>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60
Selalu ada fungsi operator atau asli yang memanggil metode ajaib ini. Terkadang itu hanya panggilan python kait dalam situasi tertentu. Sebagai contoh__init__()
dipanggil ketika objek dibuat setelah __new__()
dipanggil untuk membangun instance ...
Mari kita ambil contoh ...
class FalseCalculator(object):
def __init__(self, number):
self.number = number
def __add__(self, number):
return self.number - number
def __sub__(self, number):
return self.number + number
number = FalseCalculator(20)
print number + 10 # 10
print number - 20 # 40
Untuk detail lebih lanjut, lihat panduan PEP-8 . Untuk metode ajaib lainnya, lihat PDF ini .
Kadang-kadang Anda memiliki apa yang tampaknya menjadi tuple dengan garis bawah utama seperti pada
def foo(bar):
return _('my_' + bar)
Dalam hal ini, yang terjadi adalah _ () adalah alias untuk fungsi pelokalan yang beroperasi pada teks untuk memasukkannya ke bahasa yang tepat, dll berdasarkan pada lokal. Misalnya, Sphinx melakukan ini, dan Anda akan menemukan di antara impor
from sphinx.locale import l_, _
dan di sphinx.locale, _ () ditugaskan sebagai alias dari beberapa fungsi lokalisasi.
Karena begitu banyak orang merujuk pada pembicaraan Raymond , saya hanya akan membuatnya sedikit lebih mudah dengan menuliskan apa yang dikatakannya:
Maksud dari menggarisbawahi itu bukan tentang privasi. Niatnya adalah untuk menggunakannya persis seperti ini
class Circle(object): def __init__(self, radius): self.radius = radius def area(self): p = self.__perimeter() r = p / math.pi / 2.0 return math.pi * r ** 2.0 def perimeter(self): return 2.0 * math.pi * self.radius __perimeter = perimeter # local reference class Tire(Circle): def perimeter(self): return Circle.perimeter(self) * 1.25
Sebenarnya kebalikan dari privasi, itu semua tentang kebebasan. Itu membuat subclass Anda bebas untuk mengganti salah satu metode tanpa melanggar yang lain .
Katakanlah Anda tidak menyimpan referensi lokal perimeter
di Circle
. Sekarang, kelas turunan Tire
menimpa implementasi perimeter
, tanpa menyentuh area
. Ketika Anda menelepon Tire(5).area()
, secara teori itu masih harus digunakan Circle.perimeter
untuk perhitungan, tetapi pada kenyataannya itu menggunakanTire.perimeter
, yang bukan perilaku yang dimaksud. Itu sebabnya kami membutuhkan referensi lokal di Circle.
Tapi mengapa __perimeter
bukannya _perimeter
? Karena _perimeter
masih memberikan kelas turunan kesempatan untuk menimpa:
class Tire(Circle):
def perimeter(self):
return Circle.perimeter(self) * 1.25
_perimeter = perimeter
Double menggarisbawahi memiliki nama mangling, jadi ada kemungkinan sangat kecil bahwa referensi lokal di kelas induk mendapatkan override di kelas turunan. dengan demikian " membuat subclass Anda bebas untuk menimpa salah satu metode tanpa melanggar yang lain ".
Jika kelas Anda tidak akan diwarisi, atau metode overriding tidak merusak apa pun, maka Anda tidak perlu __double_leading_underscore
.
Jika seseorang benar-benar ingin membuat variabel read-only, IMHO cara terbaik adalah dengan menggunakan properti () dengan hanya diteruskan oleh pengambil. Dengan properti () kita dapat memiliki kontrol penuh atas data.
class PrivateVarC(object):
def get_x(self):
pass
def set_x(self, val):
pass
rwvar = property(get_p, set_p)
ronly = property(get_p)
Saya mengerti bahwa OP mengajukan pertanyaan yang sedikit berbeda, tetapi karena saya menemukan pertanyaan lain yang menanyakan 'bagaimana mengatur variabel privat' yang ditandai duplikat dengan yang satu ini, saya berpikir untuk menambahkan info tambahan ini di sini.
Menuju ke https://dbader.org/blog/meaning-of-underscores-in-python
Jawaban yang bagus dan semuanya benar. Saya telah memberikan contoh sederhana bersama dengan definisi / makna yang sederhana.
Berarti:
some_variable --► itu publik siapa pun dapat melihat ini.
_some_variable --► itu publik siapa pun dapat melihat ini tetapi itu adalah konvensi untuk menunjukkan ... peringatan pribadi tidak ada penegakan yang dilakukan oleh Python.
__some_varaible --► Python menggantikan nama variabel dengan _classname__some_varaible (nama AKA mangling) dan itu mengurangi / menyembunyikan visibilitasnya dan lebih seperti variabel pribadi.
Jujur saja di sini Menurut dokumentasi Python
Variabel instance "" Privat "yang tidak dapat diakses kecuali dari dalam suatu objek tidak ada dalam Python"
Contoh:
class A():
here="abc"
_here="_abc"
__here="__abc"
aObject=A()
print(aObject.here)
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable
#print(aObject.__here)
Garis bawah utama tunggal adalah konvensi. tidak ada perbedaan dari sudut pandang penerjemah jika apakah nama dimulai dengan garis bawah tunggal atau tidak.
Garisbaris depan dan belakang ganda digunakan untuk metode bawaan, seperti __init__
,__bool__
, dll
Menggarisbawahi terkemuka ganda tanpa rekan trailing adalah sebuah konvensi juga, namun, metode kelas akan hancur oleh penerjemah. Untuk variabel atau nama fungsi dasar tidak ada perbedaan.
Pertanyaan Anda bagus, ini bukan hanya tentang metode. Fungsi dan objek dalam modul biasanya diawali dengan satu garis bawah juga, dan dapat diawali oleh dua.
Tapi nama __double_underscore tidak di-namai dalam modul, misalnya. Apa yang terjadi adalah bahwa nama yang dimulai dengan satu (atau lebih) garis bawah tidak diimpor jika Anda mengimpor semua dari modul (dari impor modul *), juga tidak ada nama yang ditunjukkan dalam bantuan (modul).
Berikut adalah contoh ilustrasi sederhana tentang bagaimana properti garis bawah ganda dapat memengaruhi kelas yang diwarisi. Jadi dengan pengaturan berikut:
class parent(object):
__default = "parent"
def __init__(self, name=None):
self.default = name or self.__default
@property
def default(self):
return self.__default
@default.setter
def default(self, value):
self.__default = value
class child(parent):
__default = "child"
jika Anda kemudian membuat turunan anak di python REPL, Anda akan melihat di bawah ini
child_a = child()
child_a.default # 'parent'
child_a._child__default # 'child'
child_a._parent__default # 'parent'
child_b = child("orphan")
## this will show
child_b.default # 'orphan'
child_a._child__default # 'child'
child_a._parent__default # 'orphan'
Ini mungkin jelas bagi sebagian orang, tetapi itu membuat saya lengah di lingkungan yang jauh lebih kompleks
Variabel instance "Privat" yang tidak dapat diakses kecuali dari dalam suatu objek tidak ada dalam Python. Namun, ada konvensi yang diikuti oleh sebagian besar kode Python: nama diawali dengan garis bawah (misalnya _spam) harus diperlakukan sebagai bagian non-publik dari API (apakah itu fungsi, metode atau anggota data) . Ini harus dianggap sebagai detail implementasi dan dapat berubah tanpa pemberitahuan.
referensi https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
Mendapatkan fakta _ dan __ cukup mudah; jawaban lain mengekspresikannya dengan cukup baik. Penggunaannya jauh lebih sulit untuk ditentukan.
Ini adalah bagaimana saya melihatnya:
_
Harus digunakan untuk menunjukkan bahwa suatu fungsi bukan untuk penggunaan publik seperti misalnya API. Ini dan pembatasan impor membuatnya berperilaku seperti internal
di c #.
__
Harus digunakan untuk menghindari tabrakan nama dalam hirarki warisan dan untuk menghindari latebinding. Sama seperti pribadi di c #.
==>
Jika Anda ingin menunjukkan bahwa sesuatu bukan untuk penggunaan umum, tetapi harus bertindak seperti protected
digunakan _
. Jika Anda ingin menunjukkan bahwa sesuatu bukan untuk penggunaan umum, tetapi harus bertindak seperti private
digunakan__
.
Ini juga kutipan yang sangat saya sukai:
Masalahnya adalah bahwa penulis kelas dapat secara sah berpikir "atribut / nama metode ini harus pribadi, hanya dapat diakses dari dalam definisi kelas ini" dan menggunakan konvensi __private. Tetapi kemudian, pengguna kelas itu dapat membuat subclass yang secara sah membutuhkan akses ke nama itu. Jadi, superclass harus dimodifikasi (yang mungkin sulit atau tidak mungkin), atau kode subclass harus menggunakan nama-nama yang dikacaukan secara manual (yang paling jelek dan rapuh).
Tetapi masalah dengan itu menurut saya bahwa jika tidak ada IDE yang memperingatkan Anda ketika Anda mengganti metode, menemukan kesalahan mungkin butuh waktu cukup lama jika Anda secara tidak sengaja mengganti metode dari kelas dasar.