Pertanyaan Apa arti dari satu dan dua garis bawah sebelum nama objek?


Saya ingin menjernihkan ini sekali dan untuk selamanya. Dapatkah seseorang menjelaskan arti yang tepat dari memiliki menggarisbawahi underscores sebelum nama objek dengan Python? Juga jelaskan perbedaan antara garis bawah tunggal dan ganda. Juga, apakah artinya tetap sama apakah objek yang dimaksud adalah variabel, fungsi, metode, dll?


981
2017-08-19 17:15


asal


Jawaban:


Satu Underscore

Nama, di kelas, dengan garis bawah yang menonjol hanya untuk menunjukkan kepada pemrogram lain bahwa atribut atau metode dimaksudkan untuk menjadi pribadi. Namun, tidak ada yang istimewa yang dilakukan dengan nama itu sendiri.

Kutipan PEP-8:

_single_leading_underscore: indikator "penggunaan internal" lemah. Misalnya. from M import * tidak mengimpor objek yang namanya dimulai dengan underscore.

Double Underscore (Nama Pelurusan)

Dari dokumen Python:

Identifier apa pun dari formulir __spam (setidaknya dua garis bawah terkemuka, paling banyak satu garis bawah trailing) diganti secara tekstual dengan _classname__spam, dimana classname adalah nama kelas saat ini dengan garis bawah terdistorsi (s). Pembuatan ini dilakukan tanpa memperhatikan posisi sintaksis pengidentifikasi, sehingga dapat digunakan untuk menentukan instance kelas-swasta 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:

Nama mangling dimaksudkan untuk memberikan kelas cara mudah untuk mendefinisikan variabel dan metode instan "private", tanpa harus khawatir tentang variabel instan yang didefinisikan oleh kelas turunan, atau menyimpang dengan variabel instan dengan kode di luar kelas. Perhatikan bahwa aturan pengurusan dirancang sebagian besar untuk menghindari kecelakaan; masih mungkin bagi jiwa yang ditentukan untuk mengakses atau memodifikasi variabel yang dianggap pribadi.

Contoh

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

920
2017-08-19 17:52



Jawaban yang sangat baik sejauh ini tetapi beberapa tidbits hilang. Satu garis bawah utama tidak tepat hanya sebuah konvensi: jika Anda menggunakan from foobar import *, dan modul foobar tidak mendefinisikan suatu __all__ daftar, nama-nama yang diimpor dari modul tidak termasuk mereka dengan garis bawah terkemuka. Katakan saja kebanyakan sebuah konvensi, karena kasus ini adalah sudut yang cukup tidak jelas ;-).

Konvensi terkemuka-garis bawah secara luas digunakan bukan hanya untuk pribadi nama-nama, tetapi juga untuk apa yang akan dipanggil C ++ terlindung satu - misalnya, nama-nama metode yang sepenuhnya dimaksudkan untuk ditimpa oleh subclass (bahkan yang itu memiliki untuk ditimpa karena di kelas dasar mereka raise NotImplementedError! -) adalah nama yang sering digarisbawahi untuk menunjukkan kode menggunakan contoh kelas (atau subclass) yang mengatakan metode tidak dimaksudkan untuk dipanggil secara langsung.

Misalnya, untuk membuat antrian aman-thread dengan disiplin antrian yang berbeda dari FIFO, satu mengimpor Queue, subclasses Queue.Queue, dan menimpa metode seperti itu _getdan _put; "kode klien" tidak pernah memanggil mereka ("hook") metode, melainkan ("mengorganisir") metode publik seperti putdan get (ini dikenal sebagai Metode Template pola desain - lihat misalnya sini untuk presentasi yang menarik berdasarkan video dari pembicaraan saya tentang masalah ini, dengan penambahan sinopsis transkrip).


268
2017-08-19 17:21



__foo__: ini hanya konvensi, cara bagi sistem Python untuk menggunakan nama yang tidak akan bertentangan dengan nama pengguna.

_foo: ini hanya konvensi, cara bagi programmer untuk menunjukkan bahwa variabel bersifat pribadi (apa pun artinya dengan Python).

__foo: ini memiliki arti nyata: penerjemah mengganti nama ini dengan _classname__foo sebagai cara untuk memastikan bahwa nama itu tidak akan tumpang tindih dengan nama yang mirip di kelas lain.

Tidak ada bentuk lain dari garis bawah memiliki arti di dunia Python.

Tidak ada perbedaan antara kelas, variabel, global, dll dalam konvensi ini.


245
2017-08-19 17:17



._variable bersifat semiprivat dan dimaksudkan hanya untuk konvensi

.__variable sering salah dianggap sebagai superprivate, sementara itu arti sebenarnya hanya untuk namemangle to mencegah akses yang tidak disengaja[1]

.__variable__ biasanya disediakan untuk metode atau variabel bawaan

Anda masih bisa mengakses .__mangled variabel jika Anda sangat ingin. Double menggarisbawahi hanya namemangles, atau mengganti nama, variabel menjadi sesuatu seperti instance._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 menggarisbawahi nama ganda, Anda dapat mengakses nilai tersembunyi


175



Single underscore di awal:

Python tidak memiliki metode privat, jadi salah satu yang menggarisbawahi di awal metode atau nama atribut berarti Anda tidak seharusnya 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 yang diambil dari kode sumber Django (Django / forms / forms.py). Ini berarti kesalahan adalah properti, dan itu adalah bagian dari modul, 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 untuk ditimpa oleh subclass atau diakses secara tidak sengaja. Mari kita lihat contohnya:

class A(object):
    def __test(self):
        print "I'm test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()

Keluaran:

$ python test.py
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. Namun pada kenyataannya, ini adalah perilaku yang benar untuk __. Jadi, ketika Anda membuat metode yang dimulai dengan __ itu berarti bahwa Anda tidak ingin siapa pun dapat menimpanya, itu hanya dapat diakses dari dalam kelasnya sendiri.

Dua menggarisbawahi di awal dan di akhir:

Ketika kita melihat metode seperti __this__, jangan menyebutnya. Karena itu berarti itu adalah metode yang panggilan python, bukan oleh Anda. Mari lihat:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

Selalu ada operator atau fungsi asli yang memanggil metode-metode ajaib ini. Kadang-kadang itu hanya panggilan python kail 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 lebih jelasnya Panduan PEP-8 akan membantu lebih banyak.

Silakan temukan lebih banyak metode sulap di python di sini. https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf


86



Kadang-kadang Anda memiliki apa yang tampaknya menjadi tuple dengan garis bawah terkemuka seperti pada

def foo(bar):
    return _('my_' + bar)

Dalam hal ini, apa yang terjadi adalah _ () adalah alias untuk fungsi lokalisasi yang beroperasi pada teks untuk memasukkannya ke dalam bahasa yang tepat, dll berdasarkan lokal. Misalnya, Sphinx melakukan ini, dan Anda akan menemukan di antara impor

from sphinx.locale import l_, _

dan dalam sphinx.locale, _ () ditugaskan sebagai alias dari beberapa fungsi lokalisasi.


15



Underscore (_) dengan Python

Berikut ini adalah tempat yang berbeda di mana _ digunakan dengan Python:

Satu Underscore:

  • Di Interpreter
  • Setelah nama
  • Sebelum sebuah nama

Menggarisbawahi Ganda:

  • __leading_double_underscore

  • sebelum setelah

  • Satu Underscore

Dalam Interpreter:

_ mengembalikan nilai nilai ekspresi yang dieksekusi terakhir dengan Python REPL

>>> a = 10
>>> b = 10
>>> _
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> a+b
20
>>> _
20
>>> _ * 2
40
>>> _
40
>>> _ / 2
20

Untuk mengabaikan nilai:

Beberapa kali kami tidak ingin mengembalikan nilai pada waktu itu menetapkan nilai-nilai itu ke wnderscore. Ini digunakan sebagai variabel throwaway.

# Ignore a value of specific location/index
for _ in rang(10)
    print "Test"

# Ignore a value when unpacking
a,b,_,_ = my_method(var1)

Setelah nama

Python memiliki kata kunci bawaan mereka yang tidak dapat kami gunakan sebagai nama variabel. Untuk menghindari konflik antara kata kunci python dan variabel yang kami gunakan underscore setelah nama

Contoh:

>>> class MyClass():
...     def __init__(self):
...             print "OWK"

>>> def my_defination(var1 = 1, class_ = MyClass):
...     print var1
...     print class_

>>> my_defination()
1
__main__.MyClass
>>>

Sebelum sebuah nama

Leading Underscore sebelum nama variabel / fungsi / metode menunjukkan kepada programmer bahwa itu hanya untuk penggunaan internal, yang dapat dimodifikasi kapan pun kelas menginginkan.

Di sini nama awalan dengan garis bawah diperlakukan sebagai non-publik. Jika menentukan dari Impor * semua nama dimulai dengan _ tidak akan diimpor.

Python tidak menentukan benar-benar pribadi sehingga yang ini dapat dipanggil langsung dari modul lain jika ditentukan dalam semua, Kami juga menyebutnya Swasta lemah

class Prefix:
...     def __init__(self):
...             self.public = 10
...             self._private = 12
>>> test = Prefix()
>>> test.public
10
>>> test._private
12
Python class_file.py

def public_api():
    print "public api"

def _private_api():
    print "private api"

Memanggil file dari REPL

>>> from class_file import *
>>> public_api()
public api

>>> _private_api()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_private_api' is not defined

>>> import class_file
>>> class_file.public_api()
public api
>>> class_file._private_api()
private api
Double Underscore(__)

__leading_double_underscore

Memimpin garis bawah ganda memberi tahu juru bahasa python untuk menulis ulang nama agar terhindar dari konflik dalam subkelas. Interpreter mengubah nama variabel dengan ekstensi kelas dan fitur yang dikenal sebagai Mangling. testFile.py

class Myclass():
    def __init__(self):
        self.__variable = 10

Memanggil dari REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__variable
Traceback (most recent call last):
File "", line 1, in
AttributeError: Myclass instance has no attribute '__variable'
nce has no attribute 'Myclass'
>>> obj._Myclass__variable
10

Dalam Mangling python interpreter memodifikasi nama variabel dengan ___. Jadi Multiple time Ini digunakan sebagai anggota Privat karena kelas lain tidak dapat mengakses variabel itu secara langsung. Tujuan utama untuk __ adalah menggunakan variabel / metode di kelas saja. Jika Anda ingin menggunakannya di luar kelas, Anda dapat membuat api publik

class Myclass():
    def __init__(self):
        self.__variable = 10
    def func(self)
        print self.__variable

Memanggil dari REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.func()
10

__SEBELUM SETELAH__

Nama dengan awal dengan __ dan berakhir dengan yang sama menganggap metode khusus dengan Python. Python menyediakan metode ini untuk menggunakannya sebagai operator overloading tergantung pada pengguna.

Python menyediakan konvensi ini untuk membedakan antara fungsi yang ditentukan pengguna dengan fungsi modul

class Myclass():
    def __add__(self,a,b):
        print a*b

Memanggil dari REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__add__(1,2)
2
>>> obj.__add__(5,2)
10

Referensi


10



Jika seseorang benar-benar ingin membuat variabel hanya-baca, IMHO cara terbaik adalah menggunakan properti () dengan hanya getter yang dilewatkan ke sana. Dengan property () 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 pribadi' yang ditandai duplikat dengan yang satu ini, saya berpikir untuk menambahkan info tambahan ini di sini.


7



Single yang menggarisbawahi adalah konvensi. tidak ada perbedaan dari sudut pandang penafsir jika apakah nama dimulai dengan garis bawah tunggal atau tidak.

Double leading dan trailing underscores digunakan untuk metode built-in, seperti __init__, __bool__, dll.

Double menggarisbawahi garis bawah tanpa lawan bicara adalah konvensi juga, bagaimanapun, metode kelas akan kompong oleh penerjemah. Untuk variabel atau nama fungsi dasar tidak ada perbedaan.


4



Pertanyaan Anda bagus, bukan hanya tentang metode. Fungsi dan objek dalam modul umumnya diawali dengan satu garis bawah juga, dan dapat diawali oleh dua.

Namun, nama __double_underscore tidak diberi nama dalam modul, misalnya. Apa yang terjadi adalah nama yang diawali dengan satu (atau lebih) garis bawah tidak diimpor jika Anda mengimpor semua dari modul (dari modul impor *), juga nama-nama yang ditampilkan dalam bantuan (modul).


3