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


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.