Чому деякі функції мають підкреслення "__" перед і після назви функції?


424

Це "підкреслення", здається, трапляється багато, і мені було цікаво, чи це вимога мови Python, чи просто питання конвенції?

Також хтось може назвати та пояснити, які функції, як правило, мають підкреслення, і чому ( __init__наприклад)?


8
@AustinHenley: Не для подвійних підкреслень перед іменем та після нього. Ви думаєте про підкреслення виключно перед назвою.



@MackM Зауважте, що це запитання задає підкреслення перед і після імені, а дублікат цілі, який ви запропонували, запитує про підкреслення лише перед іменем. Хоча я визнаю, що деякі відповіді там стосуються і цієї справи.
Георгій

Відповіді:


526

З Python PEP 8 - Посібник зі стилю для Python Code :

Описово: Назви стилі

Розпізнаються наступні спеціальні форми, що використовують провідні або кінцеві підкреслення (вони, як правило, можуть поєднуватися з будь-якою умовою)

  • _single_leading_underscore: слабкий показник "внутрішнього використання". Напр. from M import *, Не імпортуються об'єкти, ім'я яких починається з підкреслення.

  • single_trailing_underscore_: використовується умовно, щоб уникнути конфліктів із ключовим словом Python, наприклад

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

  • __double_leading_underscore: при іменуванні атрибуту класу викликає mangling імені (всередині класу FooBar, __booстає _FooBar__boo; див. нижче).

  • __double_leading_and_trailing_underscore__: "магічні" об'єкти або атрибути, які живуть у керованих користувачем просторах імен. Наприклад __init__, __import__чи __file__. Ніколи не вигадуйте таких імен; використовувати їх лише задокументовано.

Зауважте, що імена з подвійними провідними та кінцевими підкресленнями по суті зарезервовані для самого Python: "Ніколи не вигадуйте таких імен; використовуйте їх лише як задокументовано".


6
Реймонд також пояснює, чому ви хочете, щоб це ім'я маніпулювало, починаючи приблизно з 34 хвилини цього відео: youtube.com/watch?v=HTLu2DFOdTg
johncip

5
Тож вибір між провідним підкресленням та подвійним підкресленням у назві дещо схожий на вибір між захищеним та приватним в C ++ та Java? _single_leading_underscore діти можуть змінити, але __double_leading_underscore не може?
Alex W

2
__double_leading_underscoreвсе ще є загальнодоступною , змінна просто перейменована, щоб уникнути зіткнення.
cz

59

Інші респонденти правильно описують подвійні провідні та зворотні підкреслення як умову іменування "спеціальних" чи "магічних" методів.

Хоча ви можете викликати ці методи безпосередньо ( [10, 20].__len__()наприклад), наявність підкреслень - це натяк на те, що ці методи мають бути покликані побічно ( len([10, 20])наприклад). Більшість операторів пітона мають пов'язаний з ними "магічний" метод (наприклад, a[x]звичайний спосіб виклику a.__getitem__(x)).



5

Насправді я використовую _ імена методів, коли мені потрібно відрізняти імена батьків та дочірніх класів. Я прочитав деякі коди, які використовували цей спосіб створення класів батьків-дітей. Як приклад я можу навести цей код:

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

...

і дитина, яка має метод _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)
    )

...


Чи не для цього призначений подвійний префікс підкреслення?
AMC

1

Ця умова використовується для спеціальних змінних чи методів (так званого "магічного методу"), таких як __init__і __len__. Ці методи надають особливі синтаксичні особливості або роблять спеціальні речі.

Наприклад, __file__вказує розташування файлу Python, __eq__виконується при виконанні a == bвираження.

Користувач, звичайно, може створити спеціальний спеціальний метод, що є дуже рідкісним випадком, але часто може змінювати деякі вбудовані спеціальні методи (наприклад, ви повинні ініціалізувати клас, __init__який буде виконаний спочатку, коли екземпляр класу створюється).

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

Додано приклад для розуміння використання __ у python. Ось список усіх __

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

Окремі класи ідентифікаторів (крім ключових слів) мають особливі значення. Будь-яке використання * імен у будь-якому іншому контексті, що не слідує явно задокументованому використанню, підлягає злому без попередження

Обмеження доступу за допомогою __

"""
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.