Properties und Getters

Alles, was nicht direkt mit Python-Problemen zu tun hat. Dies ist auch der perfekte Platz für Jobangebote.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

BlackJack hat geschrieben:IMHO: Das Buch ist Müll. Ich habe mit dem OOP Kapitel angefangen und da wird gleich `__del__()` als Destruktor vorgestellt, ohne jegliche Warnung warum man das nicht benutzen sollte, und "private members" mit doppelten führenden Unterstrichen um "private" Daten vor Zugriff zu schützen und sinnlose, triviale Getter und Setter per `property()` um dann darauf zuzugreifen. Argh!
Das wollte ich noch fragen. Was ist an Settern und Gettern und private members so schlecht?

Edit (Leonidas): Von "Python - Das umfassende Handbuch" abgetrennt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

burli hat geschrieben:Das wollte ich noch fragen. Was ist an Settern und Gettern und private members so schlecht?
Hallo burli!

In wenigen Worten: Sie sind meist unnötig.

Man kann einer Klasseninstanz Attribute zuweisen und diese zur Laufzeit ändern. Das funktioniert alles ohne Getter und Setter.

Getter, Setter und Properties sind nur dann nötig, wenn ich beim Abfragen oder Zuweisen einer Eigenschaft etwas ausführen möchte. Und so lange das nicht der Fall ist, kann ich das durch direktes Zuweisen eines Attributes erledigen.

Ein Python-Modul ist keine Blackbox. Den Code einer Klasse kann man anschauen. Das läuft ein wenig anders als bei C++ oder Java. Es gibt keinen Grund dafür, eine Klasseninstanz vor dem Programmierer abzuschotten.

Und für einen Python-Programmierer genügt ein Unterstrich um zu erkennen, dass ein Attribut nur intern verwendet werden soll. Aber auch bei einem Unterstrich kann der Python-Programmierer selber entscheiden, ob er das Attribut trotzdem verwendet.

Und wenn der Python-Programmierer glaubt, jemanden vor einem schlimmen Fehler bewahren zu müssen, dann kann man ein Attribut mit zwei Unterstrichen kennzeichnen. Das ist dann das Zeichen "Finger weg! Du weißt nicht was du tust!". Mit zwei Unterstichen wird dann auch das zufällige Überschreiben des Attributs verhindert, da sich der Name nach außen ändert.

Leider gibt es immer wieder Programmierer, die Unterstriche unnötig excessiv einsetzen. Man sollte diese Mittel sparsam anwenden.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

burli hat geschrieben:Das wollte ich noch fragen. Was ist an Settern und Gettern und private members so schlecht?
Weil du Getter und Setter nicht drauchst, da es in Python Properties gibt, die Getter und Setter alt aussehen lassen.

Warum gibt es in Java triviale Getter und Setter? Weil es möglich ist, dass man in Zukunft die Funktionen etwas nicht triviales berechnen lassen muss, statt einfach nur Werte zu speichern oder zu setzen. In Java will man die API nicht berechen, daher verwendet man im vorhinein Getter und Setter. In Python kann man die Attribute mit Properties wrappen, da werden Getter und Setter bei Bedarf aufgerufen, ohne dass man als Nutzer der API davon was mitbekommt. Schau dir mal die Properties-Beispiele an.

In Python gibt es keine Private Members und __ sagt auch nicht das die Variable private ist. Das ist Name Mangling und nur dazu da Namenskollisionen zu verhindern. Wenn man dem Programmierer signalisieren will, dass er ein Attribut nicht anfassen will, außer er will Breakage riskieren dann nutzt man _. Aber das ist nur Konvention.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

Um es an einem Beispiel zu zeigen:

Code: Alles auswählen

class JavaStyle(object):
    def __init__(self, spam, ham, eggs):
        self._spam = spam
        self._ham = ham
        self._eggs = eggs
    
    def get_spam(self):
        return self._spam
    
    def set_spam(self, value):
        self._spam = value
    
    def get_ham(self):
        return self._ham
    
    def set_ham(self, value):
        self._ham = value
    
    def get_eggs(self):
        return self._eggs
    
    def set_eggs(self, value):
        self._eggs = value


class PythonStyle(object):
    def __init__(self, spam, ham, eggs):
        self.spam = spam
        self.ham = ham
        self.eggs = eggs
Wenn es für ein Attribut [GS]etter gibt, ist es letztendlich doch Teil der öffentlichen API, und man kann es auch *direkt* ansprechen. Der Quelltext wird dadurch kürzer und einfacher, weil man sich eine Menge "boilerplate" Quelltext spart, der in den meisten Fällen einfach nur eine unnötige Indirektion darstellt. Sollte man so eine Indirektion später doch einmal brauchen, gibt's `property()`. Diese Möglichkeit bietet Java nicht, darum lässt man sich dort von der IDE eben viel unnützen Code erstellen, den der Compiler dann am Ende wieder wegoptimieren darf. :-)
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Dein Beispiel ergibt keinen Sinn, das ist klar. Die Setter/Getter sind ja in erster Linie dazu gedacht um zb zusätzliche Sicherheiten einzubauen. Zb das wirklich nur Integer von 0-100 geschrieben werden können.

Und das man dafür property() verwenden sollte war mir eigentlich schon klar, auch wenn es in dem Buch erstmal so wie in deinem Beispiel stand. Ok, vielleicht bin ich auch vorbelastet weil ich Propertys schon von anderen Sprachen kenne.

Warum Python allerdings kein richtiges private/public unterstützt hab ich noch nicht verstanden. Das mit den Unterstrichen ist ja bestenfalls ein Notbehelf.

Jedenfalls hätte ich nach dem Lesen des Buches "schützenswerte" Variablen mit einem Unterstrich versehen, Setter/Getter dafür geschrieben und ein Property angelegt. Korrigiert mich bitte wenn ich damit falsch liege
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo burli!
burli hat geschrieben:um zb zusätzliche Sicherheiten einzubauen. Zb das wirklich nur Integer von 0-100 geschrieben werden können.
Das ist ein guter Grund für ein Property und für einen Unterstrich im Attributnamen. Idealerweise kannst du den Wert bereits beim Eingeben in eine GUI überprüfen. Zustände die nie möglich sein dürften, kannst du zwischendurch auch mit ``assert`` checken.
burli hat geschrieben:Warum Python allerdings kein richtiges private/public unterstützt hab ich noch nicht verstanden. Das mit den Unterstrichen ist ja bestenfalls ein Notbehelf.
Vor wem willst du den Code schützen? Einem Programmierer könnte man doch wirklich zumuten, dass er ein Attribut, das mit Unterstrich beginnt, nur dann angreift wenn er weiß was er tut.

Willst du wirklich einen Fehler auslösen lassen, nur weil ein Programmierer weiß was der tut und das "private" Attribut trotzdem angreift? Unsinnig! Willst du statt dem Unterstrich wirklich Getter und Setter schreiben? Gut, kannst du machen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

In einem Perl-Buch habe ich zu dem "fehlenden" `private` einen netten Vergleich gelesen, der ungefähr so ging (Sorry, aus dem Gedächtnis): Fremde Objekte sind wie fremde Häuser. Wir gehen da nicht rein weil es unhöflich ist, und nicht weil der Besitzer einen Elektrozaun und eine Schrotflinte hat. Möchten sie in einer Nachbarschaft wohnen, in der so etwas üblich ist!?

Wenn ein Programmierer den Hinweis "das ist ein Implementierungsdetail" nur ernst nimmt, wenn es ihm die Sprache hart verbietet auf das Attribut zuzugreifen, ist das in den Augen von den meisten Pythonistas ein ernsthaftes Problem des Programmierers und nicht der Sprache. In sofern sehen wir den Unterstrich auch nicht als "Notbehelf", weil es keine Notlage gibt. Jedenfalls nicht mit der Sprache. ;-)

Andererseits gibt es halt auch immer mal wieder Fälle, wo ein Programmierer die Interna kennt und bewusst auf sie zugreift. Im Nachbarschaftsbeispiel wäre das jemand, der netterweise den Pool des Nachbarn abdeckt, bevor er seine Hecke stutzt, damit keine Blätter in den Pool geweht werden können. In einigen Sprachen nennt man so etwas `friend`. :-)
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich weiß das es im Prinzip unsinnig ist, sofern sich alle an die Regeln halten. Aber das kann keiner kontrollieren. Ganz besonders unsinnig ist es wenn den Code außer mir keiner in die Hände bekommt.

Aber völlig unsinnig sind property(Setter,Getter) auch nicht. Es geht ja nicht nur darum das der Programmierer weiß was er tut. Man kann damit ja auch Fehleingaben von Usern abfangen. Beispiel SQL Injection. Ein Setter könnte ein guter Platz sein um die ankommenden Daten auf unerwünschte Inhalte zu prüfen. Nur mal so als hypotetisches Beispiel. Ob das letztendlich sinnig ist hängt auch von der Applikation ab

Und private/protectet ist auch nicht falsch. Speziell wenn ein Programmierer die Doku nicht genau ließt und zb mit Autocomplete arbeitet. Dann sieht er alle Attribute aufgelistet, findet eins mit passendem Namen, und erwischt damit eins das er besser nicht anfassen sollte.

Auch beim Programmieren gilt: "expect the unexpected"
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

@ BlackJack: schöner Vergleich ;)

Es ist ja schön wenn Programmieren auf Vertrauensbasis funktioniert, aber garantieren kann das keiner. Manchmal vertraue ich mir ja selber nicht ;)
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

burli hat geschrieben:@ BlackJack: schöner Vergleich ;)

Es ist ja schön wenn Programmieren auf Vertrauensbasis funktioniert, aber garantieren kann das keiner. Manchmal vertraue ich mir ja selber nicht ;)
Nagut, dann baut halt jemand Mist. Er überschreibt's oder benutzt es, obwohl er es nicht sollte. Seine eigene Schuld oO' Jeder muss selber wissen, ob er in das Haus gehen möchte. Wenn er dann erschlagen wird vom Nachbarn, is's das auch.
BlackJack

@burli: Garantieren kann das auch keiner mit `private` & Co. Jemand der die Doku nicht liest, darf sich nicht beschweren, wenn etwas nicht so funktioniert, wie er sich das denkt.

Ich tendiere dazu "read only"-Attribute als solche nur zu dokumentieren und Sachen wie "Attribut `percent` must be a number between 0 and 100" ebenfalls. Wer da unbedingt 'ne Million oder was negatives zuweisen muss, fällt halt auf die Nase. Wenn mir das selbst mal passiert, schreibe ich meistens an der Stelle wo's anfing falsch zu laufen ein ``assert`` in den Quelltext.

Testen von Benutzereingaben sollte so früh wie möglich nach der Eingabe passieren, möglichst bevor die Daten in Objekte kommen, mit denen die Programmlogik implementiert ist.

Wie Du schon sagtest: "expect the unexpected", dass muss man halt machen, wenn man ohne von einem Elektrozaun aufgehalten zu werden, in einen Sumpf spazieren kann, um den lustigen Irrlichtern zu folgen. ;-)
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

BlackJack hat geschrieben:@burli: Garantieren kann das auch keiner mit `private` & Co.
Naja, kann man schon. Ich kenn es halt von anderen Sprachen wo man auch schonmal compilierte Module bekommt und nur die Schnittstelle kennt. Es kann ja durchaus sein das in dem Modul Daten verwaltet werden die keinen was angehen. Da nutzt es nichts wenn man in die Doku schreibt: Finger weg von dem Attribut. Ich würde das mal einen entscheidenden Sicherheitsaspekt nennen. (Meinem Nachbarn würde ich auch nicht die Zahlenkombination von meinem Tresor nennen in dem vertrauliche Unterlagen liegen ;) )

In Verbindung mit Python wird das ganze natürlich etwas schwammig weil es in dem Sinn keinen sicheren Code gibt. Es ist ja problemlos möglich den Bytecode zu decompilieren. Ich denke es wird keiner so dumm sein und Module in Python schreiben die irgendwie wichtig sind.

Wie auch immer, da wo es mir sinnvoll erscheint werde ich mit Properties arbeiten und Unterstriche vor Methoden und Variablen machen, auch wenn's nur eine Gedächtnisstütze ist
BlackJack

Also `private` in C++ kann man oft mit einer einfachen Deklaration vor dem importieren der Header-Datei weg bekommen: ``#define private public``. Falls das Layout von den beiden vom Compiler unterschiedlich behandelt werden sollte, kommt man via Typecast nach `*void` an die "geschützten" Daten.

In Java kann man über die Reflection-API an private Attribute und Methoden kommen.

Unter Sicherheitsaspekten sind das also keine allzu grossen Hürden für jemanden der da *wirklich* rankommen will oder muss.

Decompilieren und mit einem Debugger schrittweise verfolgen, geht auch in beiden Sprachen.

Und es gibt eine Menge Leute die Python-Module schreiben, die irgendwie wichtig sind. Wenn sie wichtig im Sinne von "darf keiner reinschauen" sind, dann darf man sie halt nicht aus der Hand geben. Wie bei eigentlich jedem Code der so wichtig ist. Das es für jedes auch nur halbwegs interessante "native binary"-Programm einen Crack oder Schlüsselgenerator gibt, beweist, dass keine Sprache gegen so etwas schützt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

burli hat geschrieben:da wo es mir sinnvoll erscheint werde ich mit Properties arbeiten und Unterstriche vor Methoden und Variablen machen, auch wenn's nur eine Gedächtnisstütze ist
Hallo burli!

Du wirst sehen, dass die Unterstriche komplett ausreichen.

Und ja, ich schreibe wichtige Module mit Python. Gerade deshalb!

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Das Schutzmaßnahmen ausgehebelt werden können ist bekannt. Erst kürzlich habe ich gesehen das man sogar relativ einfach an die Daten verschlüsselter Festplatten kommt.

Aber man muss sie auch nicht gleich auf dem Präsentierteller anbieten

Edit: Um bei dem Vergleich mit dem Haus zu bleiben. Du klebst deine TAN Liste ja auch nicht in's Fenster (public) sondern die liegt in einer Schublade (private). Aber einbrechen und die Liste klauen kann trotzdem jemand.
BlackJack

Naja irgendwo fangen Vergleiche dann an zu hinken, weil so etwas wie eine Tan-Liste oder einen Tresor gibt's IMHO nicht. Ich sehe das "privatisieren" nicht als Methode um mich oder mein "Haus" zu schützen, sondern um andere davor zu bewahren sich auf etwas zu stützen, was ich nach aussen nicht garantieren möchte. Wenn der Nachbar zum Beispiel meine elektrische `_heckenschere` mit benutzt und ich die irgendwann durch ein atomar betriebenes `_lichtschwert` ersetze, kann der Nachbar das nicht so verwenden wie bisher, weil's nicht in die Steckdose gesteckt wird und er vielleicht keine passenden Brennstäbe hat. ;-)

Wenn man wirklich einen Tresor hat, sind andere Mittel gefragt als der Zugriffsschutz, den die üblichen Programmiersprachen bieten.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

burli hat geschrieben:Das Schutzmaßnahmen ausgehebelt werden können ist bekannt. Erst kürzlich habe ich gesehen das man sogar relativ einfach an die Daten verschlüsselter Festplatten kommt.

Aber man muss sie auch nicht gleich auf dem Präsentierteller anbieten
Also Seköriti by obsköriti?

Wenn jemand dran will und er halbwegs was kann oder in der Lage ist eine Suchmaschine zu verwenden dann kommt er ran. Der Mechanismus in Java ist nicht zur Sicherheit gedacht sondern soll die Objekte kapseln. Dass man mit dem Hammer auf die Kapsel drauf hauen kann ist klar.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hi Burli!
burli hat geschrieben: Das wollte ich noch fragen. Was ist an Settern und Gettern und private members so schlecht?
Was ich mir selbst immer wieder hinter die Ohren schreibe ist, dass man getter() und setter() selten braucht. Ich bin meistens nur zu faul, das auch einzusehen. "Private" Klassenkameraden verwende ich, um auch mir selbst etwas Übersicht im Quelltext zu geben: Eine _private Methode ist nur für den (Klassen-) internen Gebrauch, ein __sehr_privates Attribut birgt beim Zugriff die Gefahr von Seiteneffekten. (Den ersten Teil davon habe ich aus PEP 8 )

Liebe Grüße

GnuShi
Marky
User
Beiträge: 24
Registriert: Donnerstag 22. Januar 2009, 08:12

Hallo Leute,

ich muss das Thema nochmal aufgreifen.
Also zunächst mal verstehe ich so manche Argumentation gegen private members nicht so ganz.
Im Grunde genommen ist doch Datenkapselung ein Paradigma objektorientierter Programmierung. Wenn man von privaten Variablen und Methoden/Funktionen spricht, dann geht es doch im Wesentlichen genau darum und nicht wie ich durch die Hintertür dann doch noch auf private Daten eines Objektes zugreifen kann.
Wenn ich zwei Softwaremodule habe, die miteinander kommunizieren, dann geht das normalerweise über Schnittstellen nach außen hin (Information Hiding).
Wenn ihr an euer Auto einen Anhänger dranhängt, dann macht ihr den doch auch an der Anhängerkupplung fest und öffnet nicht den Kofferraum und legt die Deichsel auf den Rücksitz?!

Dass in Python nichts wirklich private ist, ist ja ok und eben sprachabhängig, aber verändert das dann auch den Sinn von Datenkapselung ... ???
Gruß
Marky
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Marky hat geschrieben:Wenn ich zwei Softwaremodule habe, die miteinander kommunizieren, dann geht das normalerweise über Schnittstellen nach außen hin (Information Hiding).
Die Schnittstellen sind doch auch ohne Information Hiding da, nicht wahr? Schnittstellen definieren ja welche Protokolle vom Objekt unterstützt werden, nicht was nicht unterstützt wird.

Du kannst auch den Abschnitt zu Datenkapselung lesen, Florian beschreibt das eigentlich ganz passabel.
Marky hat geschrieben:Wenn ihr an euer Auto einen Anhänger dranhängt, dann macht ihr den doch auch an der Anhängerkupplung fest und öffnet nicht den Kofferraum und legt die Deichsel auf den Rücksitz?!
Wenn ich einen Anhänger ans Auto dranhänge, mache ich den auch nicht an einem Esel fest und binde den Esel am hinteren Scheibenwischer fest. Aber wo hat dein Vergleich irgendeine Ähnlichkeit mit OOP in Python?
Marky hat geschrieben:Dass in Python nichts wirklich private ist, ist ja ok und eben sprachabhängig, aber verändert das dann auch den Sinn von Datenkapselung ... ???
Wer sagt denn dass Datenkapselung syntaktische Unterstützung braucht? Datenkapselung in Python kannst du ja auch implizit sehen, so wie Interfaces auch. Dir werden eben weniger Hürden vor die Beine geworfen um die Datenkapselung aufzubrechen. In Java könntest du über Reflection die Kapselung überwinden, in Python über den Zugriff auf Attribute die mit ``_`` beginnen.

Es gibt auch den Ansatz: alles was dokumentiert ist, ist die Schnittstelle, der Rest ist private. Es ist eben mehr implizit und man kann über Properties Datn kapseln. Wenn jemand mutwillig hinter die Kapselung greift (das kann ja durchaus manchmal gute Gründe haben) dann ist es eben genauso möglich wie wonders auch, nur eben einfacher.

Pythons OOP-Ansatz ist weniger dogmatisch und strikt und hat nicht für alle Sachen syntaktisch/semantische Unterstützung. Ich denke gerade das ist es, was mir daran gefällt.
Antworten