Ich weiß, dass es in Python keine "echten" privaten / geschützten Methoden gibt. Dieser Ansatz soll nichts verbergen; Ich möchte nur verstehen, was Python macht.
class Parent(object):
def _protected(self):
pass
def __private(self):
pass
class Child(Parent):
def foo(self):
self._protected() # This works
def bar(self):
self.__private() # This doesn't work, I get a AttributeError:
# 'Child' object has no attribute '_Child__private'
Bedeutet dieses Verhalten also, dass "geschützte" Methoden vererbt werden, "private" jedoch überhaupt nicht?
Oder habe ich etwas vermisst?
c._Parent__private()
Antworten:
Python hat kein Datenschutzmodell, es gibt keine Zugriffsmodifikatoren wie in C ++, C # oder Java. Es gibt keine wirklich "geschützten" oder "privaten" Attribute.
Namen mit einem führenden doppelten Unterstrich und keinem nachfolgenden doppelten Unterstrich werden entstellt , um sie bei der Vererbung vor Zusammenstößen zu schützen. Unterklassen können ihre eigene
__private()
Methode definieren , und diese stören nicht den gleichen Namen in der übergeordneten Klasse. Solche Namen gelten als klassenprivat ; Sie sind immer noch von außerhalb der Klasse zugänglich, aber es ist weitaus weniger wahrscheinlich, dass sie versehentlich zusammenstoßen.Mangling wird durchgeführt, indem einem solchen Namen ein zusätzlicher Unterstrich und der Klassenname vorangestellt werden (unabhängig davon, wie der Name verwendet wird oder ob er existiert), wodurch ihnen effektiv ein Namespace zugewiesen wird . In der
Parent
Klasse wird jeder__private
Bezeichner (zur Kompilierungszeit) durch den Namen ersetzt_Parent__private
, während in derChild
Klasse der Bezeichner_Child__private
überall in der Klassendefinition durch ersetzt wird .Folgendes wird funktionieren:
class Child(Parent): def foo(self): self._protected() def bar(self): self._Parent__private()
Siehe Reservierte Klassen von Bezeichnern in der Dokumentation zur lexikalischen Analyse:
und die referenzierte Dokumentation zu Namen :
Verwenden Sie keine klassenprivaten Namen, es sei denn, Sie möchten Entwicklern, die Ihre Klasse unterordnen möchten, ausdrücklich mitteilen, dass sie bestimmte Namen nicht verwenden können oder das Risiko eingehen, Ihre Klasse zu beschädigen. Außerhalb veröffentlichter Frameworks und Bibliotheken wird diese Funktion kaum verwendet.
Der PEP 8 Python Style Guide enthält Folgendes zum Mangeln von privaten Namen:
quelle
__private()
, vielen Dank für diese klare Antwort!__getstate__()
und__setstate__()
? Ein Kind könnte diese Methoden nicht von seinem Elternteil erben?pythonic style
wenn ich versuche, alle Variablen innerhalb einer Klasse privat zu machen und danngetters
undsetters
für diese privaten Variablen zu verwenden. Nun, ich sollte diese Frage zur Verwendung privater Variablen googeln.Das
__
Doppelattribut wird geändert,_ClassName__method_name
wodurch es privater wird als die von implizierte semantische Privatsphäre_method_name
.Sie können technisch immer noch darauf zugreifen, wenn Sie es wirklich möchten, aber vermutlich wird dies niemand tun. Aus Gründen der Codeabstraktion kann die Methode zu diesem Zeitpunkt genauso gut privat sein.
class Parent(object): def _protected(self): pass def __private(self): print("Is it really private?") class Child(Parent): def foo(self): self._protected() def bar(self): self.__private() c = Child() c._Parent__private()
Dies hat den zusätzlichen Vorteil (oder einige würden sagen, der primäre Vorteil), dass eine Methode nicht mit Methodennamen von untergeordneten Klassen kollidieren darf.
quelle
Auch PEP8 sagt
Sie sollten sich
_such_methods
auch konventionell fernhalten . Ich meine, du solltest sie so behandelnprivate
quelle
Indem Sie Ihr Datenmitglied als privat deklarieren:
__private()
Sie können einfach nicht von außerhalb der Klasse darauf zugreifen
Python unterstützt eine Technik namens Name Mangling .
Diese Funktion verwandelt Klassenmitglieder mit zwei Unterstrichen in:
Wenn Sie von dort aus darauf zugreifen möchten, können
Child()
Sie Folgendes verwenden:self._Parent__private()
quelle
Obwohl dies eine alte Frage ist, bin ich darauf gestoßen und habe eine gute Lösung gefunden.
In dem Fall, in dem Sie den Namen der übergeordneten Klasse entstellt haben, weil Sie eine geschützte Funktion imitieren wollten, aber dennoch auf einfache Weise auf die Funktion der untergeordneten Klasse zugreifen möchten.
parent_class_private_func_list = [func for func in dir(Child) if func.startswith ('_Parent__')] for parent_private_func in parent_class_private_func_list: setattr(self, parent_private_func.replace("_Parent__", "_Child"), getattr(self, parent_private_func))
Die Idee ist, den übergeordneten Funktionsnamen manuell durch eine Anpassung an den aktuellen Namespace zu ersetzen. Nachdem Sie dies in die init-Funktion der untergeordneten Klasse eingefügt haben, können Sie die Funktion auf einfache Weise aufrufen.
quelle
AFAIK, im zweiten Fall führt Python "Name Mangling" durch, daher lautet der Name der __private-Methode der übergeordneten Klasse wirklich:
Und Sie können es auch nicht in dieser Form für Kinder verwenden
quelle