Was bedeuten einfacher und doppelter Unterstrich vor einem Objektnamen?

Lesezeit: 11 Minuten

Was bedeuten einfache und doppelte führende Unterstriche vor dem Namen eines Objekts in Python?

  • Eine großartige kurze Antwort aus einem anderen Thread: stackoverflow.com/a/8689983/911945

    – Anton Tarasenko

    3. Dezember 2017 um 8:33 Uhr

  • Siehe auch dies Ausgezeichnet Antwort hier, die einzelne vs. doppelte führende Unterstriche diskutiert und “Namensverstümmelung” demonstriert!: Antwort auf “Private Mitglieder in Python”

    – Gabriel Staples

    22. März 2021 um 23:53 Uhr


Benutzer-Avatar
Andreas Keeton

Einzelner Unterstrich

In einer Klasse zeigen Namen mit einem vorangestellten Unterstrich anderen Programmierern an, dass das Attribut oder die Methode innerhalb dieser Klasse verwendet werden soll. Datenschutz jedoch nicht durchgesetzt in irgendeiner Weise. Die Verwendung führender Unterstriche für Funktionen in einem Modul zeigt an, dass es nicht von woanders importiert werden sollte.

Von dem PEP-8 Gestaltungsrichtlinie:

_single_leading_underscore: schwacher Indikator für “internen Gebrauch”. Z.B from M import * importiert keine Objekte, deren Name mit einem Unterstrich beginnt.

Doppelter Unterstrich (Namensverstümmelung)

Aus die Python-Dokumentation:

Beliebiger Bezeichner des Formulars __spam (mindestens zwei führende Unterstriche, höchstens ein nachgestellter Unterstrich) wird textlich durch ersetzt _classname__spamwo classname ist der aktuelle Klassenname mit entfernten führenden Unterstrichen. Dieses Verstümmeln erfolgt ohne Rücksicht auf die syntaktische Position des Bezeichners, sodass es verwendet werden kann, um Klassen-private Instanzen und Klassenvariablen, Methoden, in Globals gespeicherte Variablen und sogar in Instanzen gespeicherte Variablen zu definieren. private für diese Klasse auf Instanzen anderer Klassen.

Und eine Warnung von derselben Seite:

Name Mangling soll Klassen eine einfache Möglichkeit geben, „private“ Instanzvariablen und Methoden zu definieren, ohne sich Gedanken über Instanzvariablen machen zu müssen, die von abgeleiteten Klassen definiert werden, oder sich mit Instanzvariablen durch Code außerhalb der Klasse herumschlagen zu müssen. Beachten Sie, dass die Mangelregeln hauptsächlich darauf ausgelegt sind, Unfälle zu vermeiden. Es ist immer noch für eine entschlossene Seele möglich, auf eine Variable zuzugreifen oder diese zu ändern, die als privat gilt.

Beispiel

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

  • Was ist, wenn ein Variablenname mit 2 Unterstrichen deklariert wurde, der nicht in der Klasse enthalten ist? Es ist dann nur eine normale Variable, oder?

    – Dhruv Ramani

    27. Juli 2015 um 8:10 Uhr


  • Diese Antwort ist äußerst irreführend, da sie den Leser zu der Annahme verleitet, dass Dunderscore verwendet wird, um Instanzattribute “superprivat” zu machen. Das ist nicht der Fall, wie hier erklärt von Raymond Hettinger, der ausdrücklich feststellt, dass Dunderscore fälschlicherweise verwendet wird, um Mitglieder als privat zu kennzeichnen, obwohl es als Gegenteil von privat konzipiert wurde.

    – Markus Meskanen

    17. Mai 2016 um 10:01 Uhr


  • @MarkusMeskanen Ich bin anderer Meinung, die Antwort besagt ausdrücklich die Verwendung eines Dunderscores, um Instanzen von Klassen-privaten Variablen und Methoden zu erstellen. Während der Dunderscore entwickelt wurde, um diese Methoden und Variablen leicht von Unterklassen überschreiben zu lassen (sie öffentlich zu machen), bewahrt die Verwendung eines Dunderscores eine private Instanz zur Verwendung innerhalb dieser Klasse.

    – arewm

    5. Juli 2016 um 15:11 Uhr

  • @MarkusMeskanen: Die Unterklassen haben die Freiheit, die gleichen Namen wie die Oberklasse zu verwenden, ohne die Oberklasse zu schlagen – mit anderen Worten, die Dunder-Namen der Oberklassen werden für sich selbst privat.

    – Ethan Furmann

    15. Juli 2016 um 17:48 Uhr

  • Bei einem einzelnen Unterstrich lautet die Antwort “mit dem Namen selbst wird nichts Besonderes gemacht”, fährt dann aber fort from M import * behandelt es anders … also etwas Besonderes ist erledigt…

    – flow2k

    11. Mai 2018 um 17:27 Uhr

Benutzer-Avatar
Ned Batchelder

  • _foo: Nur eine Konvention. Eine Möglichkeit für den Programmierer anzugeben, dass die Variable privat ist (was auch immer das in Python bedeutet).

  • __foo: Das hat wirkliche 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.

  • __foo__: Nur eine Konvention. Eine Möglichkeit für das Python-System, Namen zu verwenden, die nicht mit Benutzernamen in Konflikt stehen.

Keine andere Form von Unterstrichen hat in der Python-Welt eine Bedeutung. Außerdem gibt es in diesen Konventionen keinen Unterschied zwischen Klasse, Variable, Global usw.

  • Gerade gestoßen __foo und neugierig. Wie kann es mit ähnlichen Methodennamen mit anderen Klassen überlappen? Ich meine, Sie müssen immer noch darauf zugreifen instance.__foo()(wenn es nicht vom Interpreter umbenannt wurde), oder?

    – Bibhas Debnath

    9. Mai 2013 um 8:03 Uhr


  • Das sagt dieser Typ from module import * importiert keine Objekte mit vorangestelltem Unterstrich. Deswegen, _foo ist mehr als nur eine Konvention.

    – dotancohen

    13. Juni 2013 um 13:28 Uhr

  • @Bibhas: wenn Klasse B Unterklassen Klasse Aund beide implementieren foo()dann B.foo() überschreibt die .foo() geerbt von A. Eine Instanz von B nur darauf zugreifen können B.foo()außer über super(B).foo().

    – nichts101

    26. Januar 2015 um 3:11 Uhr

  • Zum __dunder__ Namen, implizite Aufrufe überspringen das Instanzwörterbuch, daher ist es in einigen Fällen vielleicht etwas mehr als nur eine Namenskonvention (siehe spezielle Methodensuche Abschnitt im Datenmodell).

    – Wim

    20. Februar 2020 um 20:43 Uhr

Benutzer-Avatar
Alex Martell

Hervorragende Antworten bisher, aber einige Leckerbissen fehlen. Ein einzelner führender Unterstrich ist nicht genau nur eine Konvention: wenn Sie verwenden from foobar import *und Modul foobar definiert kein __all__ list, die aus dem Modul importierten Namen unterlassen Sie Schließen Sie diejenigen mit einem führenden Unterstrich ein. Sagen wir, es ist meist eine Konvention, da dieser Fall eine ziemlich obskure Ecke ist;-).

Die Konvention des führenden Unterstrichs wird häufig nicht nur für verwendet Privatgelände Namen, sondern auch für das, was C++ aufrufen würde geschützt Einsen — zum Beispiel Namen von Methoden, die vollständig dazu bestimmt sind, von Unterklassen überschrieben zu werden (sogar solche, die haben überschrieben werden, da sie in der Basisklasse sind raise NotImplementedError!-) sind oft Namen mit einem führenden Unterstrich, um den Code anzuzeigen verwenden Instanzen dieser Klasse (oder Unterklassen), dass diese Methoden nicht direkt aufgerufen werden sollen.

Um beispielsweise eine Thread-sichere Warteschlange mit einer anderen Warteschlangendisziplin als FIFO zu erstellen, importiert man Queue, untergliedert Queue.Queue und überschreibt solche Methoden wie _get und _put; “Client-Code” ruft niemals diese (“Hook”)-Methoden auf, sondern die (“organisierenden”) öffentlichen Methoden wie z put und get (dies ist bekannt als die Vorlagenmethode Entwurfsmuster – siehe zB hier für eine interessante Präsentation basierend auf einem Video eines Vortrags von mir zu diesem Thema, mit der Ergänzung von Synopsen des Transkripts).

Edit: Die Videolinks in der Beschreibung der Vorträge sind jetzt defekt. Sie finden die ersten beiden Videos hier und hier.

  • Also, wie entscheiden Sie, ob Sie verwenden _var_name oder verwenden var_name + davon ausschließen __all__?

    – Endolith

    30. Januar 2017 um 15:39 Uhr


  • @endolith Verwenden Sie den führenden Unterstrich, um dem Leser Ihres Codes zu signalisieren, dass er dies wahrscheinlich nicht verwenden sollte (z. B. weil Sie ihn in Version 2.0 oder sogar 1.1 ändern könnten); explizit verwenden __all__ wann immer Sie das Modul machen möchten from spam import * freundlich (auch am interaktiven Dolmetscher). Also meistens lautet die Antwort beide.

    – Abart

    25. April 2018 um 17:15 Uhr

  • @AlexMartelli Wird diese importbezogene Regel irgendwo in Dokumenten oder anderswo legal diskutiert?

    – Mikrobot

    31. August 2018 um 13:12 Uhr

  • Ich mag die C++-Analogie. Erstens mag ich es nicht, wenn die Leute anrufen _ Privatgelände. Offensichtlich spreche ich von Analogien, denn nichts ist wirklich Privatgelände in Python. Wenn wir in die Semantik eintauchen, würde ich sagen, dass wir das binden können _ zu Javas geschützt seit geschützt bedeutet in Java “abgeleitete Klassen und/oder innerhalb desselben Pakets”. Paket durch Modul ersetzen, da PEP8 uns das bereits mitteilt _ ist nicht nur eine Konvention, wenn man darüber spricht * importiert und da haben Sie es. Und auf jeden Fall __ wäre äquivalent zu Java Privatgelände wenn es um Bezeichner innerhalb einer Klasse geht.

    – Marius Mucenicu

    4. Juni 2019 um 19:03 Uhr

  • Es ist zwar eine anständige Antwort, aber auch stark selbst werbend.

    – Hybride Webentwicklung

    7. Januar 2020 um 7:42 Uhr

._variable ist halbprivat und nur für Konventionen gedacht

.__variable wird oft fälschlicherweise als superprivat angesehen, während seine eigentliche Bedeutung nur darin besteht, Namen zu verfälschen versehentlichen Zugriff verhindern[1]

.__variable__ ist normalerweise für eingebaute Methoden oder Variablen reserviert

Sie können weiterhin zugreifen .__mangled Variablen, wenn Sie unbedingt wollen. Die doppelten Unterstriche ändern nur den Namen oder benennen die Variable in etwas wie um instance._className__mangled

Beispiel:

class Test(object):
    def __init__(self):
        self.__a="a"
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b ist zugänglich, weil es nur durch Konvention verborgen ist

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t.__a wird nicht gefunden, da es aufgrund von Namensverfälschung nicht mehr existiert

>>> t._Test__a
'a'

Durch den Zugriff instance._className__variable Anstelle des doppelten Unterstrichs können Sie auf den versteckten Wert zugreifen

Einfacher 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.

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(Dieses Code-Snippet stammt aus dem Django-Quellcode: django/forms/forms.py). In diesem Code errors ist eine öffentliche Eigenschaft, aber die Methode, die diese Eigenschaft aufruft, _get_errors, ist “privat”, daher sollten Sie nicht darauf zugreifen.

Zwei Unterstriche am Anfang:

Das sorgt für viel Verwirrung. Es sollte nicht verwendet werden, um eine private Methode zu erstellen. Es sollte verwendet werden, um zu vermeiden, dass Ihre Methode von einer Unterklasse überschrieben oder versehentlich darauf zugegriffen wird. Sehen wir uns ein Beispiel an:

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

Ausgabe:

$ python test.py
I'm test method in class A
I'm test method in class A

Erstellen Sie nun eine Unterklasse B und nehmen Sie Anpassungen für die Methode __test vor

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

Ausgabe wird sein….

$ python test.py
I'm test method in class A

Wie wir gesehen haben, hat A.test() keine B.__test()-Methoden aufgerufen, wie wir vielleicht erwarten würden. Tatsächlich ist dies jedoch das richtige Verhalten für __. Die beiden Methoden namens __test() werden automatisch in _A__test() und _B__test() umbenannt (entstellt), damit sie nicht versehentlich überschrieben werden. Wenn Sie eine Methode erstellen, die mit __ beginnt, bedeutet dies, dass Sie nicht möchten, dass sie von irgendjemandem überschrieben wird, und Sie beabsichtigen, nur innerhalb ihrer eigenen Klasse darauf zuzugreifen.

Zwei Unterstriche am Anfang und am Ende:

Wenn wir eine Methode wie sehen __this__, nenne es nicht. Dies ist eine Methode, die Python aufrufen soll, nicht Sie. Lass uns einen Blick darauf werfen:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

Es gibt immer einen Operator oder eine native Funktion, die diese magischen Methoden aufruft. Manchmal ist es nur ein Haken, den Python in bestimmten Situationen aufruft. Zum Beispiel __init__() wird aufgerufen, wenn das Objekt danach erstellt wird __new__() wird aufgerufen, um die Instanz zu erstellen …

Nehmen wir ein Beispiel …

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

Weitere Einzelheiten finden Sie unter PEP-8-Leitfaden. Weitere magische Methoden finden Sie unter dieses PDF.

  • Nachdem ich diese Antwort selbst bearbeitet habe, bevorzuge ich stackoverflow.com/a/8689983/1048186

    – Josiah Yoder

    21. August 2018 um 19:30 Uhr

  • Was meinen Sie mit “Wie wir gesehen haben, hat A.test() keine B.__test()-Methoden aufgerufen” – wo haben Sie A.test() aufgerufen?

    – variabel

    9. September 2019 um 15:27 Uhr

Entsprechend Bedeutung von Unterstrichen in Python

  • Einzelner führender Unterstrich (_var): Die Namenskonvention, die einen Namen angibt, ist für den internen Gebrauch bestimmt. Im Allgemeinen nicht vom Python-Interpreter erzwungen (außer bei Platzhalterimporten) und nur als Hinweis für den Programmierer gedacht.
  • Einzelner nachgestellter Unterstrich (var_): Konventionsgemäß verwendet, um Namenskonflikte mit Python-Schlüsselwörtern zu vermeiden.
  • Doppelter führender Unterstrich (__var): Löst Namensverstümmelung aus, wenn es in einem Klassenkontext verwendet wird. Vom Python-Interpreter erzwungen.
  • Doppelter führender und nachfolgender Unterstrich (__var__): Gibt spezielle Methoden an, die von der Python-Sprache definiert werden. Vermeiden Sie dieses Namensschema für Ihre eigenen Attribute.
  • Einfacher Unterstrich (_): Wird manchmal als Name für temporäre oder unbedeutende Variablen verwendet („egal“). Außerdem: Das Ergebnis des letzten Ausdrucks in einem Python ERSATZ.

  • Nachdem ich diese Antwort selbst bearbeitet habe, bevorzuge ich stackoverflow.com/a/8689983/1048186

    – Josiah Yoder

    21. August 2018 um 19:30 Uhr

  • Was meinen Sie mit “Wie wir gesehen haben, hat A.test() keine B.__test()-Methoden aufgerufen” – wo haben Sie A.test() aufgerufen?

    – variabel

    9. September 2019 um 15:27 Uhr

Manchmal erscheint ein Tupel mit einem führenden Unterstrich wie in

def foo(bar):
    return _('my_' + bar)

In diesem Fall ist _() ein Alias ​​für eine Lokalisierungsfunktion, die mit Text arbeitet, um ihn basierend auf dem Gebietsschema in die richtige Sprache usw. zu bringen. Zum Beispiel macht Sphinx dies, und Sie finden es unter den Importen

from sphinx.locale import l_, _

und in sphinx.locale wird _() als Alias ​​einer Lokalisierungsfunktion zugewiesen.

1158560cookie-checkWas bedeuten einfacher und doppelter Unterstrich vor einem Objektnamen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy