Dynamische Attribut/Variablenänderung in Klassen

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
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hallo Leute,

ich habe mal wieder ein Problem beim Erzeugen von Klassen.
Nach etwas Recherche habe ich eine Vorstellung was Klassen, Objekte, Attribute und Methoden sind. Nun will ich eine Klasse erzeugen bei dem ein Klassen Attribut von anderen abhängt und dann auch dynamisch seinen Wert ändern soll. Hier mein versuchtes Minimalbeispiel:

Code: Alles auswählen

class mainClass():
    def __init__(self):
        self.a = 3.0
        self.b = 2.0
        self.c = self.a * self.b
                
obj = mainClass()
print obj.c
obj.a = 4.0
obj.b = 5.0
print obj.c   
Am ende sollte eigentlich 20.0 da stehen. Leider bleibt der wert auf 6.0. Gibt es eine möglichkeit die Attribute der mainClass zu aktualisieren oder ist mein Ansatz falsch?
BlackJack

@schneitzmaster: Es gibt eine Möglichkeit und zwar mit `property()`. Das funktioniert aber nur zuverlässig wenn die Klasse von `object` erbt, was man in Python 2.x grundsätzlich machen sollte, wenn es keine andere Basisklasse gibt.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Um den Vorschlag von BlackJack mal in Code zu gießen:

Code: Alles auswählen

class Main1(object):
    def __init__(self, a=0.0, b=0.0):
        self.a = a
        self.b = b

    def c(self):
        return self.a * self.b

test = Main1(3.0, 2.0)
print(test.c())
test.a = 4.0
test.b = 5
print(test.c())

class Main2(object):
    def __init__(self, a=0.0, b=0.0):
        self.a = a
        self.b = b

    @property
    def c(self):
        return self.a * self.b

test = Main2(3.0, 2.0)
print(test.c)
test.a = 4.0
test.b = 5
print(test.c)
Die erste Variante ist "klassisch", die zweite mit dem property-Dekorator. Den Unterschied sieht man dann beim Aufruf.
Zuletzt geändert von /me am Donnerstag 24. Januar 2013, 09:39, insgesamt 1-mal geändert.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Super. Danke für den Tip. Ich hab unter folgendem linke eine gute Anleitung gefunden (http://www.itmaybeahack.com/book/python ... rties.html).
Das probiere ich mal.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hi /me danke für deinen Vorschlag.
Ich hab mich auch mal dran versucht und habe eine ähnliche Variante gefunden.
Ist die verwertbar oder kommt nur zufällig das heraus was ich will?

Code: Alles auswählen

class mainClass(object):
    def __init__(self):
        self.a = 3.0
        self.b = 2.0
    def varc_set( self ):
        return self.a * self.b
    c = property(varc_set)
    
          
obj = mainClass()
print obj.c
obj.a = 4.0
obj.b = 5.0
print obj.c
Welche Vorteile bringt es @property zu verwenden?
BlackJack

@schneitzmaster: Die @-Syntax ist besser lesbar weil man Anfang schon sieht dass es sich um ein `property()` handelt und nicht erst nachdem man zum Beispiel alle drei Methoden implementiert hat. Insbesondere wenn die Methoden nicht nur aus einer Zeile bestehen. `property()` ist mit ein Grund warum die @-Syntax überhaupt eingeführt wurde.

Der Name Deiner Methode für das `property()` ist übrigens falsch. Es get weder um ein `varc` (was soll das sein?[1]) noch wird da etwas gesetzt.

[1] Ich kann mir natürlich denken was damit gemeint ist, aber man kann das mit einem Unterstrich deutlicher machen.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

schneitzmaster hat geschrieben:Welche Vorteile bringt es @property zu verwenden?
Es ist eine andere Syntax die erst nach dem built-in property eingeführt wurde.

Der Name varc_set für eine Methode die ein get auf ein Attribut c durchführt ist übrigens äußerst verwirrend.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Also das varc_set sollte nur für "Variable c set" stehen. Ich hatte nicht tiefer drüber nach gedacht und wollte nur anzeigen das diese funktion der Variablen c einen Wert gibt.
@ BlackJack: So wie ich das verstanden habe wird doch genau in dieser Funktion etwas gesetzt nämlich der Wert für die Variable c bzw. ist diese Funktion für den Prozess der Wertzuweisung für c da, oder?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Nein, die Methode varc_set setzt kein Attribut c. Da ändert auch der property-Aufruf nichts dran. Es wird lediglich immer die Methode varc_set aufgerufen, wenn du das Attribut c abfragst. Bei jedem Zugriff auf c wird daher das Ergebnis neu berechnet.
Das Leben ist wie ein Tennisball.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

schneitzmaster hat geschrieben:Also das varc_set sollte nur für "Variable c set" stehen. Ich hatte nicht tiefer drüber nach gedacht und wollte nur anzeigen das diese funktion der Variablen c einen Wert gibt.
Wenn ich eine Funktion aufrufe erwarte ich eine Übereinstimmung des Namens mit dem, was ich von der Funktion möchte und nicht mit dem, was eventuell intern abläuft.

Du möchtest den Wert c haben, also wäre c_get oder auch _c_get ein geeigneter Name. Wenn du dir deinen Code mal anschaust wirst du zudem feststellen, dass es gar keine Variable c gibt, deren Wert irgendwo gesetzt würde. Der Wert wird bei jedem Aufruf dynamisch ermittelt.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Alles klar verstehe. Nur noch mal für mich zum mithämmern: Ich hätte die Funktion also auch c_dynamischBerechnen nennen können.
Langsam steige ich dahinter.
Danke noch mal
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

schneitzmaster hat geschrieben:Alles klar verstehe. Nur noch mal für mich zum mithämmern: Ich hätte die Funktion also auch c_dynamischBerechnen nennen können.
Ja, hättest du.

Um die Möglichkeiten aufzuzeigen habe ich noch mal ein kleines Beispiel mit Getter und Setter geschrieben (unter Verwendung der Dekorator-Syntax).

Code: Alles auswählen

class Test(object):
    def __init__(self):
        self._value = 0

    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, value):
        if not 0 <= value <= 10:
            raise ValueError('Invalid value {}'.format(value))
        self._value = value

test = Test()
print(test.value)
test.value = 7
print(test.value)
test.value = 11
In der letzten Zeile wird dann eine Exception geworfen, da die Prüfung beim versuchten Setzen des Wertes nicht erfolgreich war.
Antworten