Seite 1 von 1

Properties

Verfasst: Montag 5. Januar 2015, 18:05
von pixewakb
Ich habe mir die Info zu Properties bei Weigend (4. Aufl.) 2010, S. 275-276 durchgelesen, ohne sein Beispiel aus dem Buch zum Laufen zu bekommen. Ich habe jetzt mal ein Beispiel aus dem Netz gefunden. Aktuell habe ich drei Fragen:

1.) Im Kern habe ich eine Klasse, die Daten verarbeitet und mir bereitstellt, so dass ich über die Eigenschaften auf die einzelnen Werte zugreifen kann, was sehr komfortabel ist. Problem ist jetzt, dass ich manchmal nicht alle Daten brauche, d. h. die Klasse ackert enorm, um alle Daten verfügbar zu machen, abfragen will ich aber dann vielleicht nur 2, 3 Attribute. Ich habe mir jetzt überlegt, dass ich es gern so hätte, dass der Basisdatensatz immer bereitgestellt wird und der Rest nur, wenn ich ihn überhaupt explizit abfrage. Mir scheinen die Properties da geeignet, weil ich dann innerhalb der Klasse sagen kann, dass das Tool aus dem Datensatz noch Sachen nachladen soll. Gute Idee oder gibt es einen besseren Ansatz bei solchen Problemen???

2.) Muss ich die Eigenschaften auf unsichtbar stellen, um Properties zu nutzen (so bei Test und es läuft, also privates Attribut __x statt x). Ich versuche zu verstehen, warum das 2. Beispiel Fehler produziert, das erste Beispiel demgegenüber läuft. (Ich habe die Variablen angepasst, um die genaue Fehlerquelle zu finden.)

3.) Ich habe mir bislang angewöhnt, dass ich alle Eigenschaften einer Klasse vor dem Konstruktor noch mal aufführe und Anfangswerte zuweise, die dann aber meist im Konstruktor ihren eigentlichen Wert bekommen. Ich denke, dass das auf die Sachen beschränken kann, die nicht neu belegt werden. D. h. vor dem Konstruktor fehlt eine Zeile mit "x = 0". Guter/Schlechter Stil? Egal?

Code: Alles auswählen

# Properties

class Test(object):
    
    def __init__(self,x):
        self.__x = x

    def __getX(self):
        return self.__x

    def __setX(self, x):
        self.__x = x

    x = property(__getX, __setX)
        

class Test2(object):
    # produziert
    # RuntimeError: maximum recursion depth exceeded
    # self.x = variable
    def __init__(self,variableA):
        self.x = variableA

    def __getX(self):
        return self.x

    def __setX(self, variable):
        self.x = variable

    x = property(__getX, __setX)
Danke für Eure Antworten und frohes neues Jahr!

Re: Properties

Verfasst: Montag 5. Januar 2015, 18:22
von Hyperion
@1.) Gute Idee!

@2.) Jein; primäres Problem ist, dass Du im Setter gar nicht auf das zunächst in ``init`` angelegte ``x``-Objekt zugreifst, sondern auf den weiter unten über die ``property``-Funktion dann gebundenen "Getter". Dieser ruft dann aber ja *intern* wieder ``self.x``, also *wieder* die Getter-Methode auf. Das ist eben eine nicht terminierende Rekursion!
Entscheidend ist, dass der Name der Property sich vom Namen des Attributs unterscheidet. Python empfiehlt hier einen *einfachen* Unterstrich (was auch nichts mit ``private`` zu tun hat!)

Du solltest übrigens den ``@property`` Dekorator nutzen; dies heutzutage der bervorzugte Weg (auch wenn es immer noch viele Leute gibt, die die Decorator-Syntax hässlich finden :mrgreen: )

@3.) Es gibt in Python keinen Konstruktor! ``__init__`ist zumindest keiner, sondern - wie der Name andeutet - eine Methode zum *initialisieren*. Das Objekt besteht dann bereits - wie sonst könnte ein ``self``-Objekt an ``__init__`` übergeben werden ;-) Am ehesten ist ``__new__`` mit einem aus anderen Sprachen bekannten Konstruktor vergleichbar...

Zur eigentlichen Frage: Das ist kein Stilproblem, sondern ein semantischer Unterschied!

Re: Properties

Verfasst: Montag 5. Januar 2015, 18:24
von cofi
Das Problem ist, dass `self.x = ..` genau `__setX` aufruft, wenn du das in der Methode machst, hast du eben einen Rekursiven Aufruf. Weiteres Problem: Wuerde das funktionieren, wuerde das Property fuer `x` auch gar nicht mehr benutzt werden, denn jetzt gibt es ja einen Exemplarwert fuer `x`.

Darum benutzt man im Setter ueblicherweise `_x` statt `x` (und schon gar nicht `__x` wie im Buch).

Re: Properties

Verfasst: Montag 5. Januar 2015, 18:29
von mutetella
@pixewakb
``self.__x`` ist nicht ein magisch "privates" ``self.x`` sondern ein eigenes, von ``self.x`` unabhängiges Attribut. Wenn Du also bei einem ``Test2`` Exemplar das Attribut ``x`` abfragst, wird die Methode ``__getX`` aufgerufen, die wiederum ``x`` abfragt, was wiederum zu einem Aufruf von ``__getX`` führt ... .... ... Deshalb der recursion Error.
pixewakb hat geschrieben:Muss ich die Eigenschaften auf unsichtbar stellen, ...
Nein. In der Regel nutzt man halt bei Namensgleichheit des zugänglichen und des internen Attributes beim internen Attribut einen Unterstrich vor dem Namen. Damit wird klar, dass es sich hierbei um ein intern verwendetes Attribut handelt. Wenn Du also ein Attribut ``x`` hast, verwendest Du dafür intern ``_x``, könntest aber auch ``my_intern_used_x`` verwenden...

mutetella

Re: Properties

Verfasst: Montag 5. Januar 2015, 18:36
von BlackJack
@pixewakb: Ad 1.) Für so etwas kann man Properties verwenden, ja. Wobei falls ”Datensatz” hier einen aus einer SQL-Datenbank meint, ich das nicht selber programmieren würde sondern mich nach einem ORM umschauen würde das solche Aufgaben schon übernimmt oder zumindest unterstützt so etwas zu implementieren.

Ad 2.) Keine doppelten führenden Unterstriche. Ein einfacher führender Unterstrich reicht vollkommen aus und ist das Sprachmittel was für so etwas vorgesehen ist.

Die Art wie Du `property()` Verwendest ist schon länger nicht mehr aktuell. Man benutzt das als Dekorator und eine damit dekorierte Methode hat Attribute die man ihrerseits wieder als Dekoratoren für die anderen Varianten verwenden kann. Die Klasse würde dann so aussehen:

Code: Alles auswählen

class Test(object):

    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        self._value = value
Ad 3.) Verstehe ich nicht wirklich. Meinst Du das Du sinnlose *Klassen*attribute einführst? Das solltest Du sein lassen.