Seite 1 von 1
Meine eigene Klasse kennt sich selbst nicht
Verfasst: Freitag 22. April 2022, 14:50
von kopython
Das ist meine Klasse:
""" Class definition for a citrus plant. """
import random
class Citrus:
def __init__(self, species: str = None, possible_species = ("Pomelo", "Mandarin", "Citron")):
if species == None:
self.species = random.choice(possible_species)
else:
self.species = species
def __str__(self):
return "<Citrus of species " + self.species + ">"
def __add__(self, other):
if not isinstance(type(self), type(Citrus) ) or not isinstance(type(other), type(Citrus)):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
elif self.species == other.species:
return Citrus(self.species)
elif (self.species == "Pomelo" and other.species == "Mandarin") or (self.species == "Mandarin" and other.species == "Pomelo"):
return random.choice([Citrus("Sweet Orange"), Citrus("Tangerine"), Citrus("Satsuma"), Citrus("Wildleaf Mandarin"), Citrus("Bitter Orange")])
elif (self.species == "Pomelo" and other.species == "Sweet Orange") or (self.species == "Sweet Orange" and other.species == "Pomelo"):
return Citrus("Grapefruit")
elif (self.species == "Wildleaf Mandarin" and other.species == "Sweet Orange") or (self.species == "Sweet Orange" and other.species == "Wildleaf Mandarin"):
return Citrus("Clementine")
elif (self.species == "Citron" and other.species == "Bitter Orange") or (self.species == "Bitter Orange" and other.species == "Citron"):
return Citrus("Lemon")
else:
return random.choice([Citrus(self.species), Citrus(other.species)])
def __radd__(self):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
Fehlermeldung:
File "/home/.../citrus.py", line 20, in __add__
elif self.species == other.species:
AttributeError: type object 'Citrus' has no attribute 'species'
Die kommt beim verwenden der Add-Methode, was mach ich falsch?
LG
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Freitag 22. April 2022, 15:01
von __blackjack__
@kopython: Du übergibst da offenbar etwas falsches. Wäre ja nett gewesen zu sehen *was*.
Die erste ``if``-Bedingung in `__add__()` ist falsch. Die `type()`-Aufrufe haben da so überhaupt nichts zu suchen.
Und wenn man das korrigiert ist die erste Teilbedingung unsinnig, denn `self` ist *immer* ein `Citrus`-Exemplar, denn das ist ja `Citrus.__add__()`.
Die Regeln die danach folgen würde ich als Datenstruktur formulieren statt mit so viel Code. Und vielleicht nicht so verdammt viele `Citrus`-Objekte erstellen die gleich darauf wieder verworfen werden.
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Freitag 22. April 2022, 16:45
von ThomasL
Ich habe das mal etwas verändert und bei mir läuft es so:
Code: Alles auswählen
import random
variants = {("Pomelo", "Mandarin") : ("Sweet Orange", "Tangerine", "Satsuma", "Wildleaf Mandarin", "Bitter Orange"),
("Mandarin", "Pomelo") : ("Sweet Orange", "Tangerine", "Satsuma", "Wildleaf Mandarin", "Bitter Orange"),
("Pomelo", "Sweet Orange") : ("Grapefruit", ),
("Sweet Orange", "Pomelo") : ("Grapefruit", ),
("Wildleaf Mandarin", "Sweet Orange") : ("Clementine", ),
("Sweet Orange", "Wildleaf Mandarin") : ("Clementine", ),
("Citron", "Bitter Orange") : ("Lemon", ),
("Bitter Orange", "Citron") : ("Lemon", ),
}
class Citrus:
def __init__(self, species = None, possible_species = ("Pomelo", "Mandarin", "Citron")):
self.species = species or random.choice(possible_species)
def __str__(self):
return "<Citrus of species " + self.species + ">"
def __repr__(self):
return "<Citrus of species " + self.species + ">"
def __add__(self, other):
if not isinstance(other, Citrus):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
if self.species == other.species:
return Citrus(self.species)
try:
return Citrus(random.choice(variants[(self.species, other.species)]))
except KeyError:
return Citrus(random.choice([self.species, other.species]))
def __radd__(self):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Samstag 23. April 2022, 18:46
von Sirius3
Wieder so ein Fall, wo die Typannotation offensichtlich falsch ist, da der Defaultwert von `species` kein String ist.
`possible_species` wäre wohl besser eine Klassenkonstante.
Auf None testet man mit ›is‹.
Statt Strings mit + zusammenzustückeln benutzt man Format-Strings.
Bei __radd__ fehlt das zweite Argument. Aber wenn es eh nicht implementiert ist, kann man das ja auch weglassen.
Code: Alles auswählen
import random
class Citrus:
POSSIBLE_SPECIES = ["Pomelo", "Mandarin", "Citron"]
def __init__(self, species=None):
if species is None:
species = random.choice(self.POSSIBLE_SPECIES)
self.species = species
def __str__(self):
return f"<Citrus of species {self.species}>"
def __add__(self, other):
if not isinstance(other, Citrus):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
elif self.species == other.species:
return Citrus(self.species)
elif set(self.species, other.species) == {"Pomelo", "Mandarin"}:
return Citrus(random.choice(["Sweet Orange", "Tangerine", "Satsuma", "Wildleaf Mandarin", "Bitter Orange"]))
elif set(self.species, other.species) == {"Pomelo", "Sweet Orange"}:
return Citrus("Grapefruit")
elif set(self.species, other.species) == {"Wildleaf Mandarin", "Sweet Orange"}:
return Citrus("Clementine")
elif set(self.species, other.species) == {"Citron", "Bitter Orange"}:
return Citrus("Lemon")
else:
return Citrus(random.choice([self.species, other.species]))
Und ohne den Code, der die Klasse aufruft, kann man nichts zum Fehler sagen.
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Sonntag 24. April 2022, 12:04
von kopython
Vielen Dank schonmal! Ich habe den etwas schickeren Code übernommen aber hänge damit jetzt an der nächsten Stelle fest.
Der gesamte Code:
Code: Alles auswählen
""" Class definition for a citrus plant. """
import random
variants = {("Pomelo", "Mandarin") : ("Sweet Orange", "Tangerine", "Satsuma", "Wildleaf Mandarin", "Bitter Orange"),
("Mandarin", "Pomelo") : ("Sweet Orange", "Tangerine", "Satsuma", "Wildleaf Mandarin", "Bitter Orange"),
("Pomelo", "Sweet Orange") : ("Grapefruit", ),
("Sweet Orange", "Pomelo") : ("Grapefruit", ),
("Wildleaf Mandarin", "Sweet Orange") : ("Clementine", ),
("Sweet Orange", "Wildleaf Mandarin") : ("Clementine", ),
("Citron", "Bitter Orange") : ("Lemon", ),
("Bitter Orange", "Citron") : ("Lemon", ),
}
class Citrus:
def __init__(self, species = None, possible_species = ("Pomelo", "Mandarin", "Citron")):
self.species = species or random.choice(possible_species)
def __str__(self):
return "<Citrus of species %s >"% (self.species)
def __repr__(self):
return "<Citrus of species %s >"% (self.species)
def __add__(self, other):
if not isinstance(other, Citrus):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
if self.species == other.species:
return Citrus(self.species)
try:
return Citrus(random.choice(variants[(self.species, other.species)]))
except KeyError:
return Citrus(random.choice([self.species, other.species]))
def __radd__(self):
raise TypeError("plant not excepted. Both plants should be of type Citrus")
Code: Alles auswählen
""" Class definition for a garden with plants. """
from citrus import Citrus
import random
class Garden:
def __init__(self, plants: list = []) -> None:
self.plants = plants
def __len__(self):
return len(self.plants)
def __str__(self):
return "<Garden with " + str(len(self.plants)) + " plants and " + str(len(set(self.plants))) + " species> "
def plant(self, new_plant = None):
if new_plant == None :
self.plants.append(Citrus)
else:
self.plants.append(new_plant)
def cross(self):
if len(self.plants) >= 2:
crossed_citrus = random.choice(self.plants) + random.choice(self.plants)
self.plant(crossed_citrus)
Code: Alles auswählen
""" Script to simulate a garden full of citrus plants. """
from garden import Garden
from citrus import Citrus
def main():
print("\n" + "#" * 20, "Simulating Citrus", "#" * 20)
simulate_citrus()
print("\n" + "#" * 20, "Simulating Garden", "#" * 20)
simulate_garden()
def simulate_citrus():
""" Simulates instances of class Citrus. """
print("\nCreating a Citrus my_citrus ...")
my_citrus = Citrus()
print("\nPrinting my_citrus...")
print(my_citrus)
print("\nCreating a Citrus other_citrus ...")
other_citrus = Citrus()
print("\nPrinting other_citrus ...")
print(other_citrus)
print("\nPrinting my_citrus + other_citrus ...")
print(my_citrus + other_citrus)
def simulate_garden():
""" Simulates an instance of class Garden. """
print("\nCreating a Garden my_garden ...")
my_garden = Garden()
print(my_garden)
print("\nPlanting 5 Citrus plants ...")
for _ in range(5):
my_garden.plant()
print(my_garden)
print("\nCrossing plants in my_garden 20 times ...")
for _ in range(20):
my_garden.cross()
print(my_garden)
print("\nThe following species now exist in the garden:", {plant.species for plant in my_garden.plants}, "\n")
if __name__ == "__main__":
main()
Mit folgender Fehlermeldung:
Traceback (most recent call last):
File ".../simulate.py", line 59, in <module>
main()
File ".../simulate.py", line 13, in main
simulate_garden()
File ".../simulate.py", line 51, in simulate_garden
my_garden.cross()
File ".../garden.py", line 29, in cross
crossed_citrus = random.choice(self.plants) + random.choice(self.plants)
TypeError: unsupported operand type(s) for +: 'type' and 'type'
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Sonntag 24. April 2022, 13:05
von ThomasL
Nun, scheinbar funktioniert
Code: Alles auswählen
crossed_citrus = random.choice(self.plants) + random.choice(self.plants)
nicht.
Die Frage dabei ist, was ist denn in self.plants enthalten? Der Fehler (den ich gesehen habe) liegt in Garden.plant().
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Sonntag 24. April 2022, 13:31
von Sirius3
@kopython: man schreibt nicht pro Klasse ein eigenes Modul. Im jetzigen Zustand macht mehr als eine einzige Datei noch keinen Sinn.
In Garden.__init__ benutzt Du eine Liste als Defaultargument. Das ist ein schwer zu findender Fehler, denn es existiert nur eine einzige Liste für alle Garden-Instanzen. Man muß in __init__ für jede Instanz eine eigene Liste erzeugen.
Und wie ich schon geschrieben hatte, werden Strings nicht mit + zusammengestückelt, sondern man benutzt Format-Strings. Mit None wird per ›is None‹ verglichen.
Garden.plant fügt die Citrus-Klasse in self.plants ein, das ist falsch, Du willst ja eine Instanz hinzufügen.
In Garden.cross machst Du einfach nichts, wenn nicht genug Pflanzen gepflanzt worden sind; einfach nichts zu tun, ist aber oft nicht gut, weil damit Fehler schwer zu entdecken sind.
Re: Meine eigene Klasse kennt sich selbst nicht
Verfasst: Sonntag 24. April 2022, 16:46
von __blackjack__
@kopython: Die `__str__()`-Implementierungen sollten weg bzw. `__repr__()`-Implementierungen sein. Die vom `Garden` hat einen Fehler weil auch `Citrus`-Objekte mit dem gleichen `species`-Wert zwei Elemente in einem `set` sind und nicht nur einer. ``str(len(self.plants))`` ist auch unnötig umständlich wenn `self` doch selbst schon als Argument für `len()` verwendet werden kann.
Die Vorsilben `my_` und `new_` machen nicht wirklich Sinn und können weg.