Kann jemand bitte die genaue Bedeutung von führenden Unterstrichen vor dem Namen eines Objekts in Python und den Unterschied zwischen beiden erklären?
Bleibt diese Bedeutung auch gleich, ob es sich bei dem fraglichen Objekt um eine Variable, eine Funktion, eine Methode usw. handelt?
python
oop
naming-conventions
ivanleoncz
quelle
quelle
Antworten:
Einzelner Unterstrich
Namen in einer Klasse mit einem führenden Unterstrich sollen anderen Programmierern lediglich anzeigen, dass das Attribut oder die Methode privat sein soll. Mit dem Namen selbst wird jedoch nichts Besonderes gemacht.
Um PEP-8 zu zitieren :
Doppelter Unterstrich (Name Mangling)
Aus den Python-Dokumenten :
Und eine Warnung von derselben Seite:
Beispiel
quelle
__
doppelter Unterstrich als Variablenname? wiea, __ = foo()
Bisher ausgezeichnete Antworten, aber einige Leckerbissen fehlen. Ein einzelner führender Unterstrich ist nicht gerade eine Konvention: Wenn Sie verwenden
from foobar import *
und das Modulfoobar
keine__all__
Liste definiert , enthalten die aus dem Modul importierten Namen keine Namen mit einem führenden Unterstrich. Nehmen wir an, es ist meistens eine Konvention, da dieser Fall eine ziemlich dunkle Ecke ist ;-).Die Konvention zum führenden Unterstrich wird häufig nicht nur für private Namen verwendet, sondern auch für das, was C ++ als geschützte Namen bezeichnen würde - zum Beispiel für Namen von Methoden, die vollständig von Unterklassen überschrieben werden sollen (auch solche, die seitdem in überschrieben werden müssen Bei der Basisklasse handelt
raise NotImplementedError
es sich häufig um Namen mit einem führenden Unterstrich, um dem Code mithilfe von Instanzen dieser Klasse (oder Unterklassen) anzuzeigen, dass diese Methoden nicht direkt aufgerufen werden sollen.Um beispielsweise eine thread-sichere Warteschlange mit einer anderen Warteschlangendisziplin als FIFO zu erstellen, wird eine Warteschlange importiert, Queue.Queue in Unterklassen unterteilt und Methoden wie
_get
und überschrieben_put
. "Client-Code" ruft niemals diese ("Hook") Methoden auf, sondern die ("organisierenden") öffentlichen Methoden wieput
undget
(dies wird als Entwurfsmuster für Vorlagenmethoden bezeichnet - siehe z. B. hier eine interessante Präsentation basierend auf einem Video von einem Vortrag von mir zu diesem Thema, mit Hinzufügung von Synopsen des Transkripts).Bearbeiten: Die Videolinks in der Beschreibung der Vorträge sind jetzt defekt. Die ersten beiden Videos finden Sie hier und hier .
quelle
_var_name
odervar_name
+ ausschließen möchten__all__
?__all__
wann immer Sie das Modul benutzerfreundlich gestalten möchtenfrom spam import *
(auch beim interaktiven Interpreter). Die Antwort lautet also meistens beides ._
Private anrufen . Offensichtlich spreche ich von Analogien, da in Python nichts wirklich privat ist . Wenn wir in die Semantik eintauchen, würde ich sagen, dass wir das mit dem_
von Java geschützten verknüpfen können, da in Java proctected "abgeleitete Klassen und / oder innerhalb desselben Pakets" bedeutet. Ersetzen Sie das Paket durch ein Modul, da PEP8 uns bereits mitteilt, dass dies_
nicht nur eine Konvention ist, wenn es um*
Importe geht, und Sie haben es. Und__
wäre definitiv gleichbedeutend mit Javas privat, wenn es um Bezeichner innerhalb einer Klasse geht.__foo__
: Dies ist nur eine Konvention, eine Möglichkeit für das Python-System, Namen zu verwenden, die nicht mit Benutzernamen in Konflikt stehen._foo
: Dies ist nur eine Konvention, mit der der Programmierer angeben kann, dass die Variable privat ist (was auch immer das in Python bedeutet).__foo
: Dies hat eine echte Bedeutung: Der Interpreter ersetzt diesen Namen durch_classname__foo
, um sicherzustellen, dass sich der Name nicht mit einem ähnlichen Namen in einer anderen Klasse überschneidet.Keine andere Form von Unterstrichen hat in der Python-Welt eine Bedeutung.
In diesen Konventionen gibt es keinen Unterschied zwischen Klasse, Variable, Global usw.
quelle
__foo
und neugierig. Wie kann es sich mit ähnlichen Methodennamen mit anderen Klassen überschneiden? Ich meine, Sie müssen immer noch darauf zugreifeninstance.__foo()
(wenn es nicht vom Dolmetscher umbenannt wurde), oder?from module import *
keine Objekte mit Unterstrichen importiert werden. Daher_foo
ist mehr als nur eine Konvention.B
Unterklassen der KlasseA
ist und beide implementierenfoo()
, wirdB.foo()
die.foo()
geerbte Klasse überschriebenA
. Eine Instanz vonB
kann nur auf zugreifenB.foo()
, außer übersuper(B).foo()
.__dunder__
Namen überspringen implizite Aufrufe das Instanzwörterbuch , sodass es in einigen Fällen möglicherweise mehr als nur eine Namenskonvention ist (siehe Abschnitt zur Suche nach speziellen Methoden im Datenmodell).._variable
ist halbprivat und nur für Konventionen gedacht.__variable
wird oft fälschlicherweise als überprivat angesehen, während es eigentlich nur darum geht, Namen zu bündeln, um einen versehentlichen Zugriff zu verhindern [1]..__variable__
ist normalerweise für integrierte Methoden oder Variablen reserviertSie können weiterhin auf
.__mangled
Variablen zugreifen , wenn Sie dies unbedingt möchten. Das Doppel unterstreicht nur das Benennen oder Umbenennen der Variablen in etwas wieinstance._className__mangled
Beispiel:
Auf t._b kann zugegriffen werden, da es nur durch Konventionen verborgen ist
t .__ a wird nicht gefunden, da es aufgrund von Namensveränderungen nicht mehr existiert
Durch Zugriff
instance._className__variable
auf nur den doppelten Unterstrich können Sie auf den versteckten Wert zugreifenquelle
Einzelner Unterstrich am Anfang:
Python hat keine echten privaten Methoden. Stattdessen bedeutet ein Unterstrich am Anfang eines Methoden- oder Attributnamens, dass Sie nicht auf diese Methode zugreifen sollten, da sie nicht Teil der API ist.
(Dieses Code-Snippet wurde aus dem Django-Quellcode entnommen: django / forms / forms.py). In diesem Code
errors
handelt es sich um eine öffentliche Eigenschaft, aber die von dieser Eigenschaft aufgerufene Methode _get_errors ist "privat", sodass Sie nicht darauf zugreifen sollten.Zwei Unterstriche am Anfang:
Dies führt zu großer Verwirrung. Es sollte nicht zum Erstellen einer privaten Methode verwendet werden. Es sollte verwendet werden, um zu vermeiden, dass Ihre Methode von einer Unterklasse überschrieben wird oder versehentlich darauf zugegriffen wird. Sehen wir uns ein Beispiel an:
Ausgabe:
Erstellen Sie nun eine Unterklasse B und passen Sie die __test-Methode an
Ausgabe wird sein ....
Wie wir gesehen haben, hat A.test () nicht wie erwartet die Methoden B .__ test () aufgerufen. Tatsächlich ist dies jedoch das richtige Verhalten für __. Die beiden Methoden mit dem Namen __test () werden automatisch in _A__test () und _B__test () umbenannt (entstellt), sodass sie nicht versehentlich überschrieben werden. Wenn Sie eine Methode erstellen, die mit __ beginnt, bedeutet dies, dass Sie nicht möchten, dass jemand sie überschreiben kann, und dass Sie nur innerhalb der eigenen Klasse darauf zugreifen möchten.
Zwei Unterstriche am Anfang und am Ende:
Wenn wir eine Methode wie sehen
__this__
, rufen Sie sie nicht auf. Dies ist eine Methode, die Python aufrufen soll, nicht Sie. Lass uns mal sehen:Es gibt immer einen Operator oder eine native Funktion, die diese magischen Methoden aufruft. Manchmal ist es nur ein Hook, den Python in bestimmten Situationen aufruft. Wird zum Beispiel
__init__()
aufgerufen, wenn das Objekt erstellt wird, nachdem__new__()
aufgerufen wurde, um die Instanz zu erstellen ...Nehmen wir ein Beispiel ...
Weitere Informationen finden Sie im PEP-8-Handbuch . Weitere magische Methoden finden Sie in diesem PDF .
quelle
Manchmal haben Sie ein Tupel mit einem führenden Unterstrich wie in
In diesem Fall ist _ () ein Alias für eine Lokalisierungsfunktion, die Text verarbeitet, um ihn basierend auf dem Gebietsschema in die richtige Sprache usw. zu bringen. Zum Beispiel macht Sphinx dies und Sie finden unter den Importen
und in sphinx.locale wird _ () als Alias einer Lokalisierungsfunktion zugewiesen.
quelle
Da beziehen sich so viele Leute auf Raymond's Vortrag , werde ich es nur ein wenig einfacher machen, indem ich aufschreibe, was er gesagt hat:
Angenommen, Sie behalten keine lokale Referenz von
perimeter
inCircle
. JetztTire
überschreibt eine abgeleitete Klasse die Implementierung vonperimeter
, ohne sie zu berührenarea
. Wenn Sie anrufenTire(5).area()
, sollte es theoretisch immer nochCircle.perimeter
zur Berechnung verwendet werden, aber in Wirklichkeit wird es verwendetTire.perimeter
, was nicht das beabsichtigte Verhalten ist. Deshalb brauchen wir eine lokale Referenz in Circle.Aber warum
__perimeter
statt_perimeter
? weil_perimeter
abgeleitete Klassen immer noch die Möglichkeit haben, Folgendes zu überschreiben:Doppelte Unterstriche haben Namensverknüpfungen, daher besteht nur eine sehr geringe Wahrscheinlichkeit, dass die lokale Referenz in der übergeordneten Klasse in der abgeleiteten Klasse überschrieben wird. also " Ihre Unterklassen eine Methode überschreiben, ohne die anderen zu beschädigen ".
Wenn Ihre Klasse nicht vererbt wird oder das Überschreiben von Methoden nichts kaputt macht, brauchen Sie es einfach nicht
__double_leading_underscore
.quelle
Wenn man eine Variable wirklich schreibgeschützt machen möchte, ist IMHO der beste Weg, property () zu verwenden, an die nur ein Getter übergeben wird. Mit property () können wir die Daten vollständig kontrollieren.
Ich verstehe, dass OP eine etwas andere Frage gestellt hat, aber da ich eine andere Frage gefunden habe, in der gefragt wurde, wie private Variablen gesetzt werden sollen, habe ich mir überlegt, diese zusätzlichen Informationen hier hinzuzufügen.
quelle
Zu https://dbader.org/blog/meaning-of-underscores-in-python
quelle
Tolle Antworten und alle sind richtig. Ich habe ein einfaches Beispiel zusammen mit einer einfachen Definition / Bedeutung geliefert.
Bedeutung:
some_variable --► es ist öffentlich, dass jeder dies sehen kann.
_some_variable --► es ist öffentlich, jeder kann dies sehen, aber es ist eine Konvention, um privat anzuzeigen ... Warnung, dass Python keine Durchsetzung durchführt.
__some_varaible --► Python ersetzt den Variablennamen durch _classname__some_varaible (AKA name mangling) und reduziert / verbirgt die Sichtbarkeit und ähnelt eher einer privaten Variablen.
Nur um ehrlich zu sein Laut Python-Dokumentation
Das Beispiel:
quelle
Einzelne führende Unterstriche sind eine Konvention. Aus Sicht des Dolmetschers gibt es keinen Unterschied, ob Namen mit einem einzelnen Unterstrich beginnen oder nicht.
Doppel Vorder- und Hinter Unterstrichen werden verwendet für integrierte Methoden, wie zum Beispiel
__init__
,__bool__
usw.Doppelte führende Unterstriche ohne nachfolgende Gegenstücke sind ebenfalls eine Konvention, jedoch werden die Klassenmethoden vom Interpreter entstellt . Für Variablen oder grundlegende Funktionsnamen besteht kein Unterschied.
quelle
Ihre Frage ist gut, es geht nicht nur um Methoden. Funktionen und Objekten in Modulen wird normalerweise auch ein Unterstrich vorangestellt, und zwei können vorangestellt werden.
Aber __double_underscore-Namen werden beispielsweise in Modulen nicht namentlich entstellt. Was passiert ist, dass Namen, die mit einem (oder mehreren) Unterstrichen beginnen, nicht importiert werden, wenn Sie alle aus einem Modul importieren (aus Modulimport *), noch werden die Namen in der Hilfe (Modul) angezeigt.
quelle
Hier ist ein einfaches veranschaulichendes Beispiel dafür, wie sich doppelte Unterstricheigenschaften auf eine geerbte Klasse auswirken können. Also mit folgendem Setup:
Wenn Sie dann eine untergeordnete Instanz in der Python-REPL erstellen, wird Folgendes angezeigt
Für manche mag dies offensichtlich sein, aber es hat mich in einer viel komplexeren Umgebung überrascht
quelle
In Python gibt es keine "privaten" Instanzvariablen, auf die nur innerhalb eines Objekts zugegriffen werden kann. Es gibt jedoch eine Konvention, die von den meisten Python-Codes befolgt wird: Ein Name mit einem Unterstrich (z. B. _spam) sollte als nicht öffentlicher Teil der API behandelt werden (unabhängig davon, ob es sich um eine Funktion, eine Methode oder ein Datenelement handelt). . Es sollte als Implementierungsdetail betrachtet werden und kann ohne vorherige Ankündigung geändert werden.
Referenz https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
quelle
Es ist ziemlich einfach, die Fakten von _ und __ zu erfahren. Die anderen Antworten drücken sie ziemlich gut aus. Die Verwendung ist viel schwieriger zu bestimmen.
So sehe ich das:
Sollte verwendet werden, um anzuzeigen, dass eine Funktion nicht für den öffentlichen Gebrauch bestimmt ist, wie beispielsweise eine API. Dies und die Importbeschränkung bewirken, dass es sich ähnlich wie
internal
in c # verhält .Sollte verwendet werden, um eine Namenskollision in der Erbhirarchie zu vermeiden und um eine spätere Bindung zu vermeiden. Ähnlich wie privat in c #.
==>
Wenn Sie angeben möchten, dass etwas nicht für den öffentlichen Gebrauch bestimmt ist, sich aber wie ein
protected
Gebrauch verhalten sollte_
. Wenn Sie angeben möchten, dass etwas nicht für den öffentlichen Gebrauch bestimmt ist, sich aber wie einprivate
Gebrauch verhalten sollte__
.Dies ist auch ein Zitat, das mir sehr gefällt:
Das Problem dabei ist jedoch meiner Meinung nach, dass es eine Weile dauern kann, den Fehler zu finden, wenn es keine IDE gibt, die Sie beim Überschreiben von Methoden warnt, wenn Sie versehentlich eine Methode aus einer Basisklasse überschrieben haben.
quelle