Dlaczego niektóre funkcje mają podkreślenia „__” przed i po nazwie funkcji?

424

Wydaje się, że to „podkreślanie” zdarza się często i zastanawiałem się, czy to wymaganie w języku Python, czy tylko kwestia konwencji?

Ponadto, czy ktoś mógłby nazwać i wyjaśnić, które funkcje mają podkreślenia i dlaczego ( __init__na przykład)?

Chuck testa
źródło
8
@AustinHenley: Nie dla podwójnych znaków podkreślenia przed i po nazwie. Myślisz o podkreśleniach wyłącznie przed imieniem.
@MackM Pamiętaj, że to pytanie dotyczy znaków podkreślenia przed i po nazwie, a proponowany duplikat miejsca docelowego pyta o znaki podkreślenia tylko przed nazwą. Przyznaję jednak, że niektóre odpowiedzi tam również dotyczą tej sprawy.
Georgy

Odpowiedzi:

526

Z Python PEP 8 - Przewodnik po stylu dla kodu Python :

Opisowy: Style nazewnictwa

Rozpoznawane są następujące specjalne formularze wykorzystujące wiodące lub końcowe podkreślenia (można je ogólnie połączyć z dowolną konwencją przypadków):

  • _single_leading_underscore: słaby wskaźnik „do użytku wewnętrznego”. Na przykładfrom M import * Nie importuje obiektów, których nazwa zaczyna się znakiem podkreślenia.

  • single_trailing_underscore_: używane zgodnie z konwencją w celu uniknięcia konfliktów ze słowem kluczowym Python, np

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

  • __double_leading_underscore: podczas nazywania atrybutu klasy wywołuje zniekształcenie nazwy (wewnątrz klasy FooBar __boostaje się_FooBar__boo ; patrz poniżej).

  • __double_leading_and_trailing_underscore__: „magiczne” obiekty lub atrybuty, które znajdują się w kontrolowanych przez użytkownika przestrzeniach nazw. Na przykład __init__, __import__albo __file__. Nigdy nie wymyślaj takich nazw; używaj ich tylko zgodnie z dokumentacją.

Zauważ, że nazwy z podwójnymi wiodącymi i końcowymi podkreśleniami są zasadniczo zarezerwowane dla samego Pythona: „Nigdy nie wymyślaj takich nazw, używaj ich tylko zgodnie z dokumentacją”.

Michael Burr
źródło
6
Raymond wyjaśnia również, dlaczego chcesz, aby zachowanie zniekształcające nazwę zaczynało się od około 34 minut w tym filmie: youtube.com/watch?v=HTLu2DFOdTg
johncip
5
Zatem wybór między pojedynczym wiodącym podkreśleniem a podwójnym wiodącym podkreśleniem w nazwie przypomina trochę wybór między chronionym a prywatnym w C ++ i Javie? _single_leading_underscore mogą być zmieniane przez dzieci, ale __double_leading_underscore nie może?
Alex W
2
__double_leading_underscorejest nadal publiczny , zmieniono nazwę zmiennej, aby uniknąć kolizji.
cz
59

Inni respondenci słusznie opisują podwójne wiodące i końcowe znaki podkreślające jako konwencję nazewnictwa dla metod „specjalnych” lub „magicznych”.

Chociaż można wywoływać te metody bezpośrednio ( [10, 20].__len__()na przykład), obecność znaków podkreślenia jest wskazówką, że metody te mają być wywoływane pośrednio ( len([10, 20])na przykład). Większość operatorów Pythona ma powiązaną metodę „magiczną” (na przykład a[x]jest to zwykły sposób wywoływania a.__getitem__(x)).

Raymond Hettinger
źródło
5

Właściwie używam nazw metod _, gdy muszę rozróżniać nazwy klas nadrzędnych i podrzędnych. Przeczytałem kilka kodów, które wykorzystały ten sposób tworzenia klas rodzic-dziecko. Jako przykład mogę podać ten kod:

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

...

i dziecko, które ma metodę _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)
    )

...

Omadbek Onorov
źródło
Czy nie do tego służy podwójny prefiks podkreślenia?
AMC
1

Konwencja ta jest stosowana do specjalnych zmiennych lub metod (tak zwana „metoda magiczna”), takich jak __init__i __len__. Te metody zapewniają specjalne funkcje składniowe lub specjalne rzeczy.

Na przykład __file__wskazuje lokalizację pliku Python, __eq__jest wykonywany, gdya == b wyrażenia.

Użytkownik może oczywiście stworzyć niestandardową metodę specjalną, co jest bardzo rzadkim przypadkiem, ale często może zmodyfikować niektóre wbudowane metody specjalne (np. Powinieneś zainicjować klasę, __init__która zostanie wykonana na początku, gdy wystąpi klasa jest tworzone).

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
źródło
0

Dodano przykład, aby zrozumieć użycie __ w pythonie. Oto lista wszystkich __

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

Niektóre klasy identyfikatorów (oprócz słów kluczowych) mają specjalne znaczenie. Każde użycie * nazw w jakimkolwiek innym kontekście, które nie następuje po jawnie udokumentowanym użyciu, może zostać złamane bez ostrzeżenia

Ograniczenie dostępu za pomocą __

"""
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
źródło