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.?
python
oop
naming-conventions
ivanleoncz
sumber
sumber
Jawaban:
Garis Bawah Tunggal
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 :
Garis Bawah Ganda (Name Mangling)
Dari dokumen Python :
Dan peringatan dari halaman yang sama:
Contoh
sumber
__
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 modulfoobar
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") sepertiput
danget
(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 .
sumber
_var_name
atau menggunakanvar_name
+ tidak termasuk dari__all__
?__all__
kapan pun Anda ingin membuat modul inifrom 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.
sumber
__foo
dan ingin tahu. Bagaimana bisa tumpang tindih dengan nama metode yang sama dengan Kelas lainnya? Maksud saya Anda masih harus mengaksesnya sepertiinstance.__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 kelasA
, dan keduanya mengimplementasikanfoo()
, makaB.foo()
menimpa yang.foo()
diwarisi dariA
. Sebuah instance dariB
hanya akan dapat mengaksesB.foo()
, kecuali melaluisuper(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 bawaanAnda masih dapat mengakses
.__mangled
variabel jika Anda sangat ingin. Double menggarisbawahi hanya namemangles, atau mengubah nama, variabel menjadi sepertiinstance._className__mangled
Contoh:
t._b dapat diakses karena hanya disembunyikan oleh konvensi
t .__ a tidak ditemukan karena tidak ada lagi karena penamaan
Dengan mengakses
instance._className__variable
alih-alih hanya nama garis bawah ganda, Anda dapat mengakses nilai tersembunyisumber
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.
(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:
Keluaran:
Sekarang buat subclass B dan lakukan kustomisasi untuk metode __test
Output akan ....
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: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 ...
Untuk detail lebih lanjut, lihat panduan PEP-8 . Untuk metode ajaib lainnya, lihat PDF ini .
sumber
Kadang-kadang Anda memiliki apa yang tampaknya menjadi tuple dengan garis bawah utama seperti pada
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
dan di sphinx.locale, _ () ditugaskan sebagai alias dari beberapa fungsi lokalisasi.
sumber
Karena begitu banyak orang merujuk pada pembicaraan Raymond , saya hanya akan membuatnya sedikit lebih mudah dengan menuliskan apa yang dikatakannya:
Katakanlah Anda tidak menyimpan referensi lokal
perimeter
diCircle
. Sekarang, kelas turunanTire
menimpa implementasiperimeter
, tanpa menyentuharea
. Ketika Anda meneleponTire(5).area()
, secara teori itu masih harus digunakanCircle.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: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
.sumber
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.
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.
sumber
Menuju ke https://dbader.org/blog/meaning-of-underscores-in-python
sumber
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
Contoh:
sumber
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__
, dllMenggarisbawahi 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.
sumber
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).
sumber
Berikut adalah contoh ilustrasi sederhana tentang bagaimana properti garis bawah ganda dapat memengaruhi kelas yang diwarisi. Jadi dengan pengaturan berikut:
jika Anda kemudian membuat turunan anak di python REPL, Anda akan melihat di bawah ini
Ini mungkin jelas bagi sebagian orang, tetapi itu membuat saya lengah di lingkungan yang jauh lebih kompleks
sumber
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
sumber
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 sepertiprivate
digunakan__
.Ini juga kutipan yang sangat saya sukai:
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.
sumber