Tại sao một số hàm có dấu gạch dưới ____ trước và sau tên hàm?


424

Sự "nhấn mạnh" này dường như xảy ra rất nhiều, và tôi đã tự hỏi liệu đây có phải là một yêu cầu trong ngôn ngữ Python hay chỉ đơn thuần là vấn đề quy ước?

Ngoài ra, ai đó có thể đặt tên và giải thích các chức năng có xu hướng có dấu gạch dưới không, và tại sao ( __init__ví dụ)?


8
@AustinHenley: Không dành cho dấu gạch dưới kép trước và sau tên. Bạn đang nghĩ về dấu gạch dưới chỉ trước tên.



@MackM Lưu ý rằng câu hỏi này hỏi về dấu gạch dưới trước và sau tên và mục tiêu trùng lặp mà bạn đề xuất chỉ hỏi về dấu gạch dưới trước tên. Mặc dù vậy, tôi thừa nhận rằng một số câu trả lời cũng bao gồm trường hợp này.
Georgy

Câu trả lời:


526

Từ Python PEP 8 - Hướng dẫn kiểu cho mã Python :

Mô tả: Kiểu đặt tên

Các hình thức đặc biệt sau đây bằng cách sử dụng dấu gạch dưới hàng đầu hoặc dấu vết được nhận dạng (chúng thường có thể được kết hợp với bất kỳ quy ước trường hợp nào):

  • _single_leading_underscore: chỉ số "sử dụng nội bộ" yếu. Ví dụ: from M import *không nhập các đối tượng có tên bắt đầu bằng dấu gạch dưới.

  • single_trailing_underscore_: được sử dụng bởi quy ước để tránh xung đột với từ khóa Python, vd

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

  • __double_leading_underscore: khi đặt tên một thuộc tính lớp, gọi tên xáo trộn (bên trong lớp FooBar, __bootrở thành _FooBar__boo; xem bên dưới).

  • __double_leading_and_trailing_underscore__: Các đối tượng hoặc thuộc tính "ma thuật" sống trong không gian tên do người dùng kiểm soát. Ví dụ __init__, __import__hoặc __file__. Không bao giờ phát minh ra tên như vậy; chỉ sử dụng chúng như tài liệu.

Lưu ý rằng các tên có dấu gạch dưới hàng đầu và dấu hai lần về cơ bản được dành riêng cho Python: "Không bao giờ phát minh ra các tên đó; chỉ sử dụng chúng như tài liệu".


6
Raymond cũng giải thích lý do tại sao bạn muốn hành vi xáo trộn tên bắt đầu từ khoảng 34 phút trong video này: youtube.com/watch?v=HTLu2DFOdTg
johncip

5
Vì vậy, sự lựa chọn giữa dấu gạch dưới hàng đầu duy nhất và dấu gạch dưới hàng đầu kép trong một tên có giống như lựa chọn giữa được bảo vệ và riêng tư trong C ++ và Java không? Trẻ em có thể thay đổi _single_lead_underscore, nhưng __double_lead_underscore thì không?
Alex W

2
__double_leading_underscorevẫn công cộng , biến chỉ đơn giản là đổi tên để tránh một cuộc đụng độ.
cz

59

Những người trả lời khác là chính xác trong việc mô tả hai dấu gạch đầu và dấu gạch dưới như một quy ước đặt tên cho các phương pháp "đặc biệt" hoặc "ma thuật".

Mặc dù bạn có thể gọi các phương thức này trực tiếp ( [10, 20].__len__()ví dụ), sự hiện diện của dấu gạch dưới là một gợi ý rằng các phương thức này được dự định sẽ được gọi gián tiếp ( len([10, 20])ví dụ). Hầu hết các toán tử python có một phương thức "ma thuật" liên quan (ví dụ, a[x]là cách gọi thông thường a.__getitem__(x)).



5

Trên thực tế tôi sử dụng tên phương thức _ khi tôi cần khác nhau giữa tên lớp cha và lớp con. Tôi đã đọc một số mã sử dụng cách tạo lớp cha-con này. Để làm ví dụ tôi có thể cung cấp mã này:

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

...

và đứa trẻ có phương pháp _worker

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

...


Đây không phải là những gì tiền tố gạch dưới đôi dành cho?
AMC

1

Quy ước này được sử dụng cho các biến hoặc phương thức đặc biệt (được gọi là phương thức ma thuật của Hồi giáo) như __init____len__. Những phương pháp này cung cấp các tính năng cú pháp đặc biệt hoặc làm những điều đặc biệt.

Ví dụ: __file__chỉ ra vị trí của tệp Python, __eq__được thực thi khia == b biểu thức được thực thi.

Tất nhiên người dùng có thể tạo một phương thức đặc biệt tùy chỉnh, một trường hợp rất hiếm, nhưng thường có thể sửa đổi một số phương thức đặc biệt có sẵn (ví dụ: bạn nên khởi tạo lớp với __init__nó sẽ được thực thi ngay từ đầu khi một thể hiện của lớp được tạo ra).

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

0

Đã thêm một ví dụ để hiểu việc sử dụng __ trong python. Đây là danh sách của tất cả __

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

Một số lớp định danh (bên cạnh từ khóa) có ý nghĩa đặc biệt. Bất kỳ việc sử dụng tên * nào, trong bất kỳ bối cảnh nào khác, không tuân theo việc sử dụng tài liệu rõ ràng, đều có thể bị phá vỡ mà không có cảnh báo

Hạn chế truy cập bằng cách sử dụng __

"""
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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.