Warum haben einige Funktionen vor und nach dem Funktionsnamen den Unterstrich „__“?


424

Dieses "Unterstreichen" scheint häufig vorzukommen, und ich habe mich gefragt, ob dies eine Anforderung in der Python-Sprache oder nur eine Frage der Konvention ist.

Könnte jemand auch benennen und erklären, welche Funktionen die Unterstriche haben und warum ( __init__zum Beispiel)?


8
@AustinHenley: Nicht für doppelte Unterstriche vor und nach dem Namen. Sie denken an Unterstriche nur vor dem Namen.



@MackM Beachten Sie, dass in dieser Frage nach Unterstrichen vor und nach dem Namen gefragt wird und das von Ihnen vorgeschlagene doppelte Ziel nur vor dem Namen nach Unterstrichen fragt . Ich gebe jedoch zu, dass einige der Antworten dort auch diesen Fall abdecken.
— Georgy

Antworten:


526

Aus dem Python PEP 8 - Style Guide für Python-Code :

Beschreibend: Benennungsstile

Die folgenden Sonderformen mit führenden oder nachfolgenden Unterstrichen werden erkannt (diese können im Allgemeinen mit jeder Konvention kombiniert werden):

  • _single_leading_underscore: schwacher "interner Gebrauch" Indikator. ZB from M import *importiert beispielsweise keine Objekte, deren Name mit einem Unterstrich beginnt.

  • single_trailing_underscore_: Wird gemäß Konvention verwendet, um Konflikte mit dem Python-Schlüsselwort zu vermeiden, z

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

  • __double_leading_underscore: Ruft beim Benennen eines Klassenattributs die Namensverknüpfung auf (innerhalb der Klasse FooBar __boowird _FooBar__boo; siehe unten).

  • __double_leading_and_trailing_underscore__: "magische" Objekte oder Attribute, die in benutzergesteuerten Namespaces leben. Zum Beispiel __init__, __import__oder __file__. Erfinde niemals solche Namen. Verwenden Sie sie nur wie dokumentiert.

Beachten Sie, dass Namen mit doppelt führenden und nachfolgenden Unterstrichen im Wesentlichen Python selbst vorbehalten sind: "Erfinden Sie solche Namen niemals, verwenden Sie sie nur wie dokumentiert".


6
Raymond erklärt auch, warum Sie das Verhalten des Namens Mangling ab etwa 34 Minuten in diesem Video haben
— möchten

5
Die Wahl zwischen dem einfach führenden Unterstrich und dem doppelt führenden Unterstrich in einem Namen ist also ein bisschen wie die Wahl zwischen geschützt und privat in C ++ und Java? _single_leading_underscore kann von Kindern geändert werden, __double_leading_underscore jedoch nicht?
— Alex W

2
__double_leading_underscoreist nach wie vor der Öffentlichkeit , wird die Variable einfach umbenannt einen Zusammenstoß zu vermeiden.
— cz

59

Die anderen Befragten beschreiben die doppelt führenden und nachfolgenden Unterstriche zu Recht als Namenskonvention für "spezielle" oder "magische" Methoden.

Während Sie diese Methoden direkt aufrufen können ( [10, 20].__len__()zum Beispiel), ist das Vorhandensein der Unterstriche ein Hinweis darauf, dass diese Methoden indirekt aufgerufen werden sollen ( len([10, 20])zum Beispiel). Den meisten Python-Operatoren ist eine "magische" Methode zugeordnet (z. B. a[x]die übliche Methode zum Aufrufen a.__getitem__(x)).



5

Eigentlich verwende ich _ Methodennamen, wenn ich zwischen übergeordneten und untergeordneten Klassennamen unterscheiden muss. Ich habe einige Codes gelesen, die diese Art der Erstellung von Eltern-Kind-Klassen verwendeten. Als Beispiel kann ich diesen Code bereitstellen:

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

...

und das Kind, das eine _worker-Methode hat

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

...


Ist das nicht der Zweck des doppelten Unterstrichpräfixes?
— AMC

1

Diese Konvention wird für spezielle Variablen oder Methoden (sogenannte „magische Methode“) wie __init__und verwendet __len__. Diese Methoden bieten spezielle syntaktische Funktionen oder führen spezielle Aktionen aus.

Gibt beispielsweise __file__den Speicherort der Python-Datei an und __eq__wird ausgeführt, wenn der a == bAusdruck ausgeführt wird.

Ein Benutzer kann natürlich eine benutzerdefinierte spezielle Methode __init__erstellen , was ein sehr seltener Fall ist, aber häufig einige der integrierten speziellen Methoden ändert (z. B. sollten Sie die Klasse damit initialisieren , die zuerst ausgeführt wird, wenn eine Instanz einer Klasse ausgeführt wird geschaffen).

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

Es wurde ein Beispiel hinzugefügt, um die Verwendung von __ in Python zu verstehen. Hier ist die Liste aller __

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

Bestimmte Klassen von Bezeichnern (neben Schlüsselwörtern) haben spezielle Bedeutungen. Jede Verwendung von * Namen in einem anderen Kontext, die nicht der explizit dokumentierten Verwendung folgt, kann ohne Vorwarnung unterbrochen werden

Zugriffsbeschränkung mit __

"""
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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.