Seite 1 von 1

Instanz Attribut als Klassvariable

Verfasst: Sonntag 24. Februar 2019, 18:20
von d_rose
Hallo,
ist es möglich eine eigentlich als Instanzattribut gedachte Variable, in einer anderen Klasse als Klassenattribut zu setzen.
Folgendes Beispiel:
Eine Klasse Fahrzeug mit den Attributen Räderanzahl, Nutzlast, usw.
Eine Klasse Fahrzeug welche von Fahrzeug erbt.
Und anschließend ein Klasse Fahrrad, welche von PKW erbt aber immer genau 2 Räder hat.

Wenn ich das so lese, so denke ich das die Klasse Fahrrad die Räderanzahl als Klassenvariable haben muss.
Aber gleichzeitig erbt sie von PKW welche als Attribut auch eine Räderanzahl verlangt, was sich ineffizient erweist, da ich ja dann zwei Räderanzahlen hätte.
Gibt es irgendeine elegante Art und Weise das zu machen ?

Re: Instanz Attribut als Klassvariable

Verfasst: Sonntag 24. Februar 2019, 18:22
von ThomasL
Ich stelle den Gedanken, Fahrrad als eine Unterklasse von PKW zu betrachten, stark in Frage.

Re: Instanz Attribut als Klassvariable

Verfasst: Sonntag 24. Februar 2019, 19:00
von Perlchamp
@d_rose:
Eine Klasse Fahrzeug mit den Attributen Räderanzahl, Nutzlast, usw.
Eine Klasse Fahrzeug welche von Fahrzeug erbt.
Und anschließend ein Klasse Fahrrad, welche von PKW erbt aber immer genau 2 Räder hat
ein und diesselbe Klasse (Fahrzeug), die voneinander erbt? ich bin Anfänger, weiß auch nicht, ob das geht, aber dies klingt beim Lesen bereits abenteuerlich.
Meist entstehen Programme (und daraus Klassen, etc.) aus dem Bezug (oder in Anlehnung) zur Wirklichkeit. Aber Fahhrad als Unterklasse von Farhrzeug (im Sinne von PKW) zu definieren empfinde ich bereits als unrealistisch.

Re: Instanz Attribut als Klassvariable

Verfasst: Sonntag 24. Februar 2019, 19:19
von sls
d_rose hat geschrieben: Sonntag 24. Februar 2019, 18:20 Hallo,
ist es möglich eine eigentlich als Instanzattribut gedachte Variable, in einer anderen Klasse als Klassenattribut zu setzen.
Ein Klassenattribut ist für alle Instanzen dieser Klasse gleich, wird also geteilt, während Instanzattribute nur für die jeweiligen Instanzen gelten, also verschieden sein können.
d_rose hat geschrieben: Sonntag 24. Februar 2019, 18:20 Folgendes Beispiel:
Eine Klasse Fahrzeug mit den Attributen Räderanzahl, Nutzlast, usw.
Eine Klasse Fahrzeug welche von Fahrzeug erbt.
Und anschließend ein Klasse Fahrrad, welche von PKW erbt aber immer genau 2 Räder hat.

Wenn ich das so lese, so denke ich das die Klasse Fahrrad die Räderanzahl als Klassenvariable haben muss.
Aber gleichzeitig erbt sie von PKW welche als Attribut auch eine Räderanzahl verlangt, was sich ineffizient erweist, da ich ja dann zwei Räderanzahlen hätte.
Gibt es irgendeine elegante Art und Weise das zu machen ?
Alle Eigenschaften, also Attribute die du beschreibst sind Instanzattribute, da die Anzahl der Räder von der Art der Kindklasse abhängig sind. Wenn Fahrrad ein Kind von Fahrzeug ist, dann hat Fahrrad die Eigenschaften / Attribute von Fahrzeug (z.B. Bremsen, Räder, usw.), nur dass für diese Instanz eben die Anzahl der Räder unterschiedlich ist. Für PKW gilt dann eben etwas anderes.

Klassenattribute sind hier IMHO nicht sinnvoll, da keine der Eigenschaften fix ist, und für alle erbenden Klassen gleich.

Re: Instanz Attribut als Klassvariable

Verfasst: Sonntag 24. Februar 2019, 23:07
von __blackjack__
Ein Klassenattribut könnte hier ins Spiel kommen wenn die Anzahl der Räder grundsätzlich vom Typ abhängt, also wenn alle PKW vier Räder haben und alle Fahräder zwei Räder haben und beide von Fahrzeug abgeleitet sind, könnte man die Anzahl der Räder als Klassenattribut modellieren.

Re: Instanz Attribut als Klassvariable

Verfasst: Sonntag 24. Februar 2019, 23:38
von sls
@__blackjack__:

Meinst du das so in der Art?

Code: Alles auswählen

>>> class Fahrzeug:
...     pass
... 
>>> class PKW(Fahrzeug):
...     RAEDER = 4
... 
>>> class Fahrrad(Fahrzeug):
...     RAEDER = 2
... 
>>> 
>>> 
>>> pkw = PKW()
>>> fahrrad = Fahrrad()
>>> pkw.RAEDER
4
>>> fahrrad.RAEDER
2
Andere Variante, weil man ja sagen könnte dass Fahrzeug auch irgendwie RAEDER als Klassenattribut haben muss / kann / soll.

Code: Alles auswählen

class Fahrzeug:
    RAEDER = 4

class PKW(Fahrzeug):
    pass

class Fahrrad(Fahrzeug):
    RAEDER = 2

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 00:48
von __deets__
Das Fahrzeug 4 Räder hat ist nicht sinnvoll. Dann ist es besser den Wert auf None oder ggf 0 zu setzten.

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 09:16
von Sirius3
@__deets__: dass Fahrzeuge prinzipiell 0 Räder haben, bezweifle ich dann doch.

Fahrzeug sieht für mich wie eine abstrakte Klasse aus, die halt noch nicht vollständig ist, wenn es keine RAEDER gibt, wobei ANZAHL_RAEDER der bessere Name wäre.

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 10:48
von __blackjack__
Ich würde Fahrzeug in dem Fall ``ANZAHL_RAEDER = None`` verpassen, weil die Klasse ja als Basis für die Dokumentation von gemeinsamen Eigenschaften und Verhalten dient und man dort dann etwas hat wo man die Dokumentation dran heften kann. (Ich benutze Sphinx und damit kann man auch direkt die Attribute dokumentieren und muss das nicht mit in den DocString der Klasse schreiben.) Oder einen konkreten Wert wenn ich erwarte, dass die meisten abgeleiteten Klassen den sowieso setzen werden und das nur in Ausnahmefällen anders belegt wird.

Also eigentlich ganz korrekt ja:

Code: Alles auswählen

class Fahrzeug(ABC):
    """"Abstrakte Fahrzeug Basisklasse."""
    
    #: Anzahl der Räder.
    ANZAHL_RAEDER: ClassVar[Optional[int]] = None
🤡

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 11:01
von __deets__
Ich benutze auch meistens None wenn die Basisklasse keinen sinnvollen Wert annehmen kann. Ggf. ein object()-Sentinel. Aber die Delkaration von dem Typ zeigt eine Schwaeche auf - er ist ja eben genau *nicht* optional...

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 11:20
von __blackjack__
Na gut, dann nur:

Code: Alles auswählen

class Fahrzeug(ABC):
    """"Abstrakte Fahrzeug Basisklasse."""
    
    #: Anzahl der Räder.
    ANZAHL_RAEDER: ClassVar[int]
Wobei das `Optional` ja nicht bedeutet das man es weglassen kann, sondern nur das es auch `None` sein darf. Und mit Typannotationen erzwingen das es auf einen Wert gesetzt wird, kann man AFAIK nicht.

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 12:10
von __deets__
Genau das wollte ich damit auch beleuchten - das ist eben eine Schwaeche des Typsystems. Java kennt ja nicht umsonst ein eigenes Schluesselwort dafuer. Und mE ist die Gefahr, durch einen Typen zu kommunizieren "hier kannst du auch optional sein" fataler, als es gar nicht zu tun.

Die Loesung bestaende natuerlich im Zweifel darin, eine abstrakte Methode einuzfuehren, und die Konstante damit zu ersetzen. Was ein bisschen traurig macht...

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 12:41
von __blackjack__
@__deets__: Wie würde man das denn in Java machen? Also in der abstrakten Basisklasse ein statisches Feld vorgeben ohne dort einen Wert anzugeben und damit zu erzwingen das abgeleitete Klassen da etwas konkretes angeben müssen? Ich würde in Java auch über eine abstrakte Methode gehen, wobei das in Java weniger schmerzt weil man da ja sowieso triviale Getter Implementiert und gewohnt ist. Beziehungsweise könnte man da ja einen konkreten Getter implementieren und das statische Feld mit einem ungültigen Wert belegen auf den der Getter prüft. Ist dann natürlich erst eine Prüfung zur Laufzeit.

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 13:01
von __deets__
Klassenvariablen kann man in Java dafuer eh nicht nehmen. Das *muss* eine abstrakte Methode sein, weil Java ja auch keinen dynamischen Dispatch per Klasse fuer Klassenattribute/statische Variablen erlaubt, wie bei Python. Nur Methoden koennen das.

Ich kenne die Python-Typ-Annotationen und damit verbundenen Checker nicht gut genug, aber theoretisch zumindest sollte das ueberladen einer Property die dann per Deskriptor zur class-property wird auch moeglich sein. Aber da wird's langsam rostig, weil solche Sperenzchen eigentlich schon lange nicht mehr zum meinem Arsenal gehoeren - weniger meta ist mehr dieser Tage...

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 13:07
von __blackjack__
Jo, früher war mehr Lameta… 🤡

Re: Instanz Attribut als Klassvariable

Verfasst: Montag 25. Februar 2019, 17:48
von Perlchamp
@ d_rose:
mir stellt sich immer noch die Frage, warum Fahrrad von PKW erben *muss* (oder umgekehrt), also was diese beiden Klassen miteinander verbindet. Ein Fahrrad und ein PKW haben doch in der Realität auch kaum Gemeinsamkeiten, was willst du da vererben ?
Es gibt doch mit Sicherheit auch eine andere Möglichkeit, dies zu lösen. Welche Gemeinsamkeiten haben denn die beiden Klassen in deinem Script? Gibt's da überhaupt welche (wenn es bereits bei den Räder/Reifen hapert)?