Insanziierung einer Klasse verhindern?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Laut meinen Infos ist der tatsächliche Konstruktor einer Klasse nicht für mich zugänglich. __init__ ist kein ctor.

Mit C++ habe ich den ctor private gemacht, um zu verhindern, dass von der Klasse Instanzen erzeugt werden können bzw. damit nur die Klasse selbst sich instanziieren kann (Factory).

Geht das auch mit Python?
Ich möchte verhindern, dass irgendjemand von Außen eine Instanz davon erzeugen kann.

Oder könnte man dafür sorgen, dass nur eine Instanz der Klasse existiert und keine zweite erzeugt werden kann? ;)
BlackJack

@MoonKid: Du erzeugst einfach nur ein Exemplar und beginnst den Klassennamen mit einem Unterstrich damit der Leser weiss dass das keine Name ist den er benutzen sollte. Ich habe so ein bisschen das Gefühl das Python nicht für Dich ist. :-)
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

MoonKid hat geschrieben:Ich möchte verhindern, dass irgendjemand von Außen eine Instanz davon erzeugen kann.
Der einfachste Ansatz sieht sicher so aus.

Code: Alles auswählen

class Foobar(object):
    def __new__(cls):
        raise NotImplementedError('Don\'t instantiate this class')
Jetzt müsstest du noch ein wenig Code schreiben um dann aus einer Klassenmethode heraus doch wieder die Instanziierung zu ermöglichen. Code dieser Art kann aber natürlich auch jeder schreiben der die Klasse benutzt, so dass du nicht verhindern kannst, dass trotzdem ein Exemplar erzeugt wird.

Wenn es dir im Endeffekt nur darum geht ein Singleton zu haben, dann gibt es dafür eigentlich eine relativ einfache Lösung. Im Netz findest du durchaus Singleton-Implementierungen für Python oder mit dem Borg-Pattern die Python-Version davon. Ich finde das akademisch ganz nett, aber es versucht im Endeffekt Python das mit Gewalt aufzuzwingen, wofür Python nicht gebaut ist und was Python gar nicht haben will. Langer Rede kurzer Sinn: Pack die Daten einfach in ein Modul, das ist bereits ein Singleton. Punkt.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@MoonKid: so etwas wie "privat" gibt es in Python nicht. Das erlaubt einem, neben den offiziellen Wegen auch inoffizielle Wege zu gehen. Es mußt nur klar sein, was der offizielle Weg ist, und das kannst Du ganz einfach in der Dokumentation tun. So in einem roten Kästchen: "Don't instantiate this class directly. Use function xy instead."
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Sirius3 hat geschrieben:so etwas wie "privat" gibt es in Python nicht
Kannst du das belegen? Nutze noch nicht lange Python, aber kenne Klassen-member, welche mit doppelten Unterstrich beginnen. Die sind meines Wissens "private".

Mit der Modullösung kann ich gut leben...
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Es gibt nur private per Konvention. Dies sind Attribute, welche mit einem Unterstrich beginnen. Doppelte, führende Unterstriche werden im Bezug der Mehrfachvererbung (so gut wie nie) benötigt.

Wenn Du ein Buch/Tutorial verwendest, welche so private Attribute tituliert, nimm ein anderes ;)

Wenn meine Klassen nicht direkt erzeugt werden sollen, verwende ich einen führenden Unterstrich beim Klassennamen und eine freie Funktion, um eine Instanz zu erzeugen.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

bwbg hat geschrieben:Es gibt nur private per Konvention. Dies sind Attribute, welche mit einem Unterstrich beginnen. Doppelte, führende Unterstriche werden im Bezug der Mehrfachvererbung (so gut wie nie) benötigt.
Was du beschreibst sind protected-member. private/protected/public sind feststehende und von der Prog-Sprache unabhängige Begriffe der OOP.
Mir ist klar, das einiges "lockerer" gesehen wird bei Python, aber die Unterscheidung sollte schon sein.

"per Konvention"?

http://www.python-kurs.eu/python3_klassen.php
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

MoonKid hat geschrieben:Was du beschreibst sind protected-member. private/protected/public sind feststehende und von der Prog-Sprache unabhängige Begriffe der OOP.
Mir ist klar, das einiges "lockerer" gesehen wird bei Python, aber die Unterscheidung sollte schon sein.
Nein, bwbg hat das schon ganz richtig beschrieben. Einfacher führender Unterstrich für private Methoden, doppelter führender Unterstrich zur Vermeidung von Namenskollisionen.
MoonKid hat geschrieben:"per Konvention"?
Ja, per Konvention.
Gut, damit wäre dann auch bestätigt, dass du ein schlechtes Tutorial verwendest. Vielleicht hättest du einfach mal das offizielle verwenden sollen:
https://docs.python.org/2/tutorial/classes.html#tut-private hat geschrieben:“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
Das Leben ist wie ein Tennisball.
BlackJack

@MoonKid: So ganz unabhängig sind die Begriffe nicht, denn man muss die ja im Kontext der jeweiligen Programmiersprache irgendwie abbilden. Insofern hat Python tatsächlich kein `private` oder `protected` denn alle Attribute sind technisch gesehen `public`, denn man kommt an alle heran. An die mit einem führenden Unterstrich, die halt nur per Konvention ”private” sind, und an die mit zwei führenden Unterstrichen kommt man auch heran, denn das „name mangeling” ist nicht als Zugriffsschutz gedacht, sondern um bei Mehrfachvererbung Namenskollisionen zu vermeiden in dem der Klassenname mit in den Attributnamen eingebaut wird:

Code: Alles auswählen

class A(object):
    def __init__(self, value=42):
        self.__not_private = value

    def __repr__(self):
        return '{0.__class__.__name__}({1!r})'.format(self, self.__not_private)


def main():
    a = A()
    print(a)
    a._A__not_private = 23
    print(a)
Man kommt da also problemlos dran.
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Antworten