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

Chuck Testa
quelle
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".

Michael Burr
quelle
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)).

Raymond Hettinger
quelle
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)
    )

...

Omadbek Onorov
quelle
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
Shagun Pruthi
quelle
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
Hitesh Sahu
quelle