Mengapa beberapa fungsi memiliki garis bawah “__” sebelum dan sesudah nama fungsi?

425

Ini "menggarisbawahi" tampaknya banyak terjadi, dan saya bertanya-tanya apakah ini adalah persyaratan dalam bahasa Python, atau hanya masalah konvensi?

Juga, bisakah seseorang memberi nama dan menjelaskan fungsi mana yang cenderung memiliki garis bawah, dan mengapa ( __init__, misalnya)?

Chuck Testa
sumber
8
@AustinHenley: Bukan untuk menggarisbawahi ganda sebelum dan sesudah nama. Anda sedang memikirkan garis bawah hanya di depan nama.
@MackM Perhatikan bahwa pertanyaan ini menanyakan tentang garis bawah sebelum dan sesudah nama, dan target rangkap yang Anda ajukan bertanya tentang garis bawah hanya di depan nama. Padahal, saya akui bahwa beberapa jawaban di sana mencakup kasus ini juga.
Georgy

Jawaban:

527

From the Python PEP 8 - Panduan Gaya untuk Kode Python :

Deskriptif: Gaya Penamaan

Bentuk khusus berikut yang menggunakan garis bawah awal atau akhir dikenali (ini biasanya dapat dikombinasikan dengan konvensi kasus apa pun):

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

  • single_trailing_underscore_: digunakan oleh konvensi untuk menghindari konflik dengan kata kunci Python, mis

    Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore: ketika menamai atribut kelas, panggil nama mangling (di dalam kelas FooBar, __boomenjadi _FooBar__boo; lihat di bawah).

  • __double_leading_and_trailing_underscore__: "sihir" objek atau atribut yang hidup di ruang nama yang dikontrol pengguna. Misalnya __init__, __import__atau __file__. Jangan pernah menemukan nama seperti itu; hanya menggunakannya seperti yang didokumentasikan.

Perhatikan bahwa nama dengan menggarisbawahi garis depan dan belakang ganda pada dasarnya dicadangkan untuk Python: "Jangan pernah menciptakan nama-nama seperti itu; gunakan saja itu seperti yang didokumentasikan".

Michael Burr
sumber
6
Raymond juga menjelaskan mengapa Anda ingin nama mangling behaviour dimulai sekitar 34 menit dalam video ini: youtube.com/watch?v=HTLu2DFOdTg
johncip
5
Jadi pilihan antara underscore terkemuka tunggal dan underscore terkemuka ganda dalam nama agak mirip dengan memilih antara terproteksi dan privat dalam C ++ dan Java? _single_leading_underscore dapat diubah oleh anak-anak, tetapi __double_leading_underscore tidak bisa?
Alex W
2
__double_leading_underscoremasih bersifat publik , variabel diubah namanya untuk menghindari bentrokan.
cz
59

Responden lain benar dalam menggambarkan garisbawah ganda memimpin dan tertinggal sebagai konvensi penamaan untuk metode "khusus" atau "ajaib".

Meskipun Anda dapat memanggil metode ini secara langsung ( [10, 20].__len__()misalnya), keberadaan garis bawah adalah petunjuk bahwa metode ini dimaksudkan untuk dipanggil secara tidak langsung ( len([10, 20])misalnya). Sebagian besar operator python memiliki metode "sihir" yang terkait (misalnya, a[x]adalah cara yang biasa digunakan a.__getitem__(x)).

Raymond Hettinger
sumber
5

Sebenarnya saya menggunakan nama metode _ ketika saya harus berbeda antara nama kelas orang tua dan anak. Saya telah membaca beberapa kode yang menggunakan cara ini untuk membuat kelas orangtua-anak. Sebagai contoh saya dapat memberikan kode ini:

class ThreadableMixin:
   def start_worker(self):
       threading.Thread(target=self.worker).start()

   def worker(self):
      try:
        self._worker()
    except tornado.web.HTTPError, e:
        self.set_status(e.status_code)
    except:
        logging.error("_worker problem", exc_info=True)
        self.set_status(500)
    tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.results))

...

dan anak yang memiliki metode _pekerja

class Handler(tornado.web.RequestHandler, ThreadableMixin):
   def _worker(self):
      self.res = self.render_string("template.html",
        title = _("Title"),
        data = self.application.db.query("select ... where object_id=%s", self.object_id)
    )

...

Omadbek Onorov
sumber
Bukankah ini untuk awalan garis bawah ganda?
AMC
1

Konvensi ini digunakan untuk variabel atau metode khusus (disebut "metode ajaib") seperti __init__dan __len__. Metode-metode ini menyediakan fitur sintaksis khusus atau melakukan hal-hal khusus.

Misalnya, __file__menunjukkan lokasi file Python, __eq__dieksekusi ketika a == bekspresi dieksekusi.

Seorang pengguna tentu saja dapat membuat metode khusus khusus, yang merupakan kasus yang sangat jarang, tetapi sering dapat memodifikasi beberapa metode khusus bawaan (misalnya Anda harus menginisialisasi kelas dengan __init__yang akan dieksekusi pada awalnya ketika turunan sebuah kelas dibuat).

class A:
    def __init__(self, a):  # use special method '__init__' for initializing
        self.a = a
    def __custom__(self):  # custom special method. you might almost do not use it
        pass
Shagun Pruthi
sumber
0

Menambahkan contoh untuk memahami penggunaan __ dalam python. Berikut adalah daftar Semua __

https://docs.python.org/3/genindex-all.html#_

Kelas pengidentifikasi tertentu (selain kata kunci) memiliki arti khusus. Setiap penggunaan * nama, dalam konteks lain, yang tidak mengikuti penggunaan yang didokumentasikan secara eksplisit, dapat rusak tanpa peringatan

Pembatasan akses menggunakan __

"""
Identifiers:
-  Contain only (A-z, 0-9, and _ )
-  Start with a lowercase letter or _.
-  Single leading _ :  private
-  Double leading __ :  strong private
-  Start & End  __ : Language defined Special Name of Object/ Method
-  Class names start with an uppercase letter.
-

"""


class BankAccount(object):
    def __init__(self, name, money, password):
        self.name = name            # Public
        self._money = money         # Private : Package Level
        self.__password = password  # Super Private

    def earn_money(self, amount):
        self._money += amount
        print("Salary Received: ", amount, " Updated Balance is: ", self._money)

    def withdraw_money(self, amount):
        self._money -= amount
        print("Money Withdraw: ", amount, " Updated Balance is: ", self._money)

    def show_balance(self):
        print(" Current Balance is: ", self._money)


account = BankAccount("Hitesh", 1000, "PWD")  # Object Initalization

# Method Call
account.earn_money(100)

# Show Balance
print(account.show_balance())

print("PUBLIC ACCESS:", account.name)  # Public Access

# account._money is accessible because it is only hidden by convention
print("PROTECTED ACCESS:", account._money)  # Protected Access

# account.__password will throw error but account._BankAccount__password will not
# because __password is super private
print("PRIVATE ACCESS:", account._BankAccount__password)

# Method Call
account.withdraw_money(200)

# Show Balance
print(account.show_balance())

# account._money is accessible because it is only hidden by convention
print(account._money)  # Protected Access
Hitesh Sahu
sumber