Hallo zusammen,
Ich lerne gerade Python und habe gehört, dass man es vermeiden soll, Funktionen in Schleifen zu definieren. Gilt das selbe auch für if else Bedingungen oder nur für Schleifen?
Funktionen in Schleifen definieren?
-
- User
- Beiträge: 13
- Registriert: Sonntag 16. Mai 2021, 10:20
@Sirius3
Ich baue ein Programm, welches entsprechend der Benutzereingabe das Volumen eines Körpers ausrechnen soll. Ich würde mir jetzt die Funktionen für die Berechnung innerhalb der if (elif) Zweige für die einzelnen Körper definieren. Verstehst du wie ich meine?
Ich baue ein Programm, welches entsprechend der Benutzereingabe das Volumen eines Körpers ausrechnen soll. Ich würde mir jetzt die Funktionen für die Berechnung innerhalb der if (elif) Zweige für die einzelnen Körper definieren. Verstehst du wie ich meine?
- noisefloor
- User
- Beiträge: 4195
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
nee, du möchtest die Funktionen für die verschiedenen Körper außerhalb definieren und rufst du passende Funktion dann innerhalb der if-elif-else Kaskade auf.
Warum meinst du, dass das innerhalb einer if-Bedingung definiert werden muss? Zeig' am besten mal deinen Code, dann kann man konkreter darüber reden.
Gruß, noisefloor
nee, du möchtest die Funktionen für die verschiedenen Körper außerhalb definieren und rufst du passende Funktion dann innerhalb der if-elif-else Kaskade auf.
Warum meinst du, dass das innerhalb einer if-Bedingung definiert werden muss? Zeig' am besten mal deinen Code, dann kann man konkreter darüber reden.
Gruß, noisefloor
Du kannst den Code innerhalb der if-Zweige anlegen. Oder ihn in Funktionen auslagern, die dann innerhalb der if-Zweige aufgerufen werden. Das ist zumeist auch lesbarer. Rein grammatikalisch ist auch die Definition einer Funktion innerhalb der if-Zweige möglich. Das ist aber aus einer Vielzahl von Gründen eine schlechte Idee. Womit wir bei der Frage von @Sirius3 wären, falls Du dies vor hast.
-
- User
- Beiträge: 13
- Registriert: Sonntag 16. Mai 2021, 10:20
@ noisefloor
Hier ist mein Code. Er funktioniert auch soweit. Ihr könnt mir ja mal sagen, ob der so ok ist oder nach Clean Code Prinzipien absoluter Mist:
Hier ist mein Code. Er funktioniert auch soweit. Ihr könnt mir ja mal sagen, ob der so ok ist oder nach Clean Code Prinzipien absoluter Mist:
Code: Alles auswählen
print("Das ist ein Volumerechner.")
choosed_operation = input("Bitte wähle zuerst deinen Körper: 1 für Würfel, 2 für Quader, 3 für Kugel, "
"4 für Zylinder, 5 für Kegel: ")
if choosed_operation == str(1):
def volume_cube(a, rnd):
volume = a ** 3
volume = round(volume, rnd)
return volume, a
choosed_a = float(input("Bitte gib die Länge der Seite a an: "))
choosed_rounds = int(input("Bitte gib deine Nachkomastellen an: "))
volume, a = volume_cube(choosed_a, choosed_rounds)
print("Bei einer Seitenlänge von a = " + str(a) + " ist das Volumen: " + str(volume))
elif choosed_operation == str(2):
def volume_cuboid(a, b, c, roundpoint):
volume = a * b * c
volume = round(volume, roundpoint)
return a, b, c, volume, roundpoint
choosed_a = float(input("Länge a eingeben: "))
choosed_b = float(input("Länge b eingeben: "))
choosed_c = float(input("Länge c eingeben: "))
choosed_roundpoints = int(input("Nachkommastellen eingeben: "))
a, b, c, volume, roundpoint = volume_cuboid(choosed_a, choosed_b, choosed_c, choosed_roundpoints)
print("Bei a = ", str(a), " und b = ", str(b), "und c = ", str(c), " ist dein Volumen: ", str(volume))
elif choosed_operation == str(3):
def volume_bullet(radius, rounds):
pi = 3.14159
volume = 4/3 * pi * radius ** 3
volume = round(volume, rounds)
return pi, volume, radius
choosed_radius = float(input("Bitte gib deinen gewünschten Radius ein: "))
choosed_round = int(input("Bitte gib deine Nachkommastellen an: "))
pi, vol, rad = volume_bullet(choosed_radius, choosed_round)
print("Bei einem Radius von " + str(choosed_radius) + " ist das Volumen: " + str(vol) +
"\nIn der Formel wird für pi " + str(pi) + " verwendet.")
elif choosed_operation == str(4):
def volume_cylinder(radius, height, rounds):
pi = 3.14159
volume_cylinder = pi * radius ** 2 * height
volume_cylinder = round(volume_cylinder, rounds)
return pi, height, volume_cylinder, radius
user_rad = float(input("Bitte gib deinen Radius ein: "))
user_height = float(input("Bitte gib deine Höhe ein: "))
user_round = int(input("Bitte gib deine Nachkomastellen an: "))
pi, height, volume_cylinder, radius = volume_cylinder(user_rad, user_height, user_round)
print("Bei einem Radius von", str(user_rad), "und einer Höhe von", str(user_height), "ist das Volumen", str(volume_cylinder),
"\nIn der Formel wird für pi = ", pi, "verwendet.")
elif choosed_operation == str(5):
def volume_cone(radius, height, roundnumbers):
pi = 3.14159
volume_cone = pi * radius ** 2 * height / 3
volume_cone = round(volume_cone, roundnumbers)
return pi, radius, height, volume_cone
user_radius = float(input("Bitte gib deinen Radius ein: "))
user_height = float(input("Bitte gib deine Höhe ein: "))
user_rounds = int(input("Bitte gib deine Nachkommastellen an: "))
pi, radius, height, volume_cone = volume_cone(user_radius, user_height, user_rounds)
print("Bei einem Radius von", str(radius), "und einer Höhe von", str(height), "ist das Volumen:", str(volume_cone),
"\nIn der Formel wird für pi = ", str(pi), "verwendet.")
else:
print("keine gültige Eingabe.")
- noisefloor
- User
- Beiträge: 4195
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
also wie gesagt die Funktionen gehören außerhalb der if-elif-else Kaskaden definiert. Macht den Code leserlicher und, falls du deine Datei woanders importierst könnten die Funktionen auch extern verwendet werden.
Ansonsten solltest du Variablennamen einheitlich benennen, als nicht mal rnd, rounds, roundpoint. Die Anzahl der Nachkommastellen bezeichnet man im englischen in der Regel auch eher als "precision".
Kugel heißt auf Englisch "sphere" und "choosed" gibt es nicht. Grammatikalisch korrekt ist "chosen".
Strings formatiert man seit Python 3.6 mit f-Strings. Alternativ geht auch die format-Methoden von Strings, eine Verkettung mit Kommas funktioniert zwar, ist aber unschön nicht nicht typisch pythonisch.
Gruß, noisefloor
also wie gesagt die Funktionen gehören außerhalb der if-elif-else Kaskaden definiert. Macht den Code leserlicher und, falls du deine Datei woanders importierst könnten die Funktionen auch extern verwendet werden.
Ansonsten solltest du Variablennamen einheitlich benennen, als nicht mal rnd, rounds, roundpoint. Die Anzahl der Nachkommastellen bezeichnet man im englischen in der Regel auch eher als "precision".
Kugel heißt auf Englisch "sphere" und "choosed" gibt es nicht. Grammatikalisch korrekt ist "chosen".
Strings formatiert man seit Python 3.6 mit f-Strings. Alternativ geht auch die format-Methoden von Strings, eine Verkettung mit Kommas funktioniert zwar, ist aber unschön nicht nicht typisch pythonisch.
Gruß, noisefloor
Hallo,
man würde die Funktionen wie schon erwähnt nicht in der if-Bedingung definieren. Python besitzt normal eine Funktion mit dem Namen 'main' daraus wird das Programm gesteuert sprich Funktionen aufgerufen, Argumente übergeben und Rückgaben der Funktionen entgegen genommen. Dein Programm mal auf eine Berechnung gekürzt, könnte man das so aufbauen:
Schau dir mal die Strings in 'print' an. Da muss man nichts mehr mit '+' zusammen puzzeln, das Stichwort hier ist f-Strings.
Grüße
Dennis
Edit: Okay, die englischen Bezeichnungen habe ich von dir übernommen und unschön an meinem Code ist, das ich jetzt deutsch mit englisch gemischt habe, das macht man nicht, sorry.
man würde die Funktionen wie schon erwähnt nicht in der if-Bedingung definieren. Python besitzt normal eine Funktion mit dem Namen 'main' daraus wird das Programm gesteuert sprich Funktionen aufgerufen, Argumente übergeben und Rückgaben der Funktionen entgegen genommen. Dein Programm mal auf eine Berechnung gekürzt, könnte man das so aufbauen:
Code: Alles auswählen
#!/usr/bin/env python3
def volume_cube(seitenlaenge, nachkommastelle):
return round(seitenlaenge ** 3, nachkommastelle)
def main():
print("Das ist ein Volumerechner.")
choosed_operation = input("Bitte wähle zuerst deinen Körper: 1 für Würfel: ")
if choosed_operation == "1":
choosed_a = float(input("Bitte gib die Länge der Seite a an: "))
choosed_rounds = int(input("Bitte gib deine Nachkomastellen an: "))
print(
f"Bei einer Seitenlänge von a = {choosed_a} ist das Volumen: {volume_cube(choosed_a, choosed_rounds)}"
)
else:
print("keine gültige Eingabe.")
if __name__ == "__main__":
main()
Grüße
Dennis
Edit: Okay, die englischen Bezeichnungen habe ich von dir übernommen und unschön an meinem Code ist, das ich jetzt deutsch mit englisch gemischt habe, das macht man nicht, sorry.
Zuletzt geändert von Dennis89 am Dienstag 17. August 2021, 20:03, insgesamt 1-mal geändert.
"When I got the music, I got a place to go" [Rancid, 1993]
Das Problem ist, wenn man Funktionen mitten im Code definiert, dass man sie nicht einzeln testen kann. Daneben wird das ziemlich unübersichtlich. Auch wiederspricht es dem Prinzip, dass man ja Funktionen wiederverwenden will, also wenn Du an einer anderen Stelle nochmal das Volumen berechnen willst.
str(1) ist das selbe wie "1". Strings stückelt man nicht mit + zusammen, sondern verwendet Format-Strings.
Man rundet nicht explizit, sondern erst bei der Ausgabe, per Formatangabe.
Werte, die man als Argument einer Funktion übergibt, muß man nicht mehr als Rückgabewert wieder zurückgeben.
Präfixe wie user_ oder choosen_ sind überflüssig, weil sie dem Leser keinen Mehrwert bieten.
str(1) ist das selbe wie "1". Strings stückelt man nicht mit + zusammen, sondern verwendet Format-Strings.
Man rundet nicht explizit, sondern erst bei der Ausgabe, per Formatangabe.
Werte, die man als Argument einer Funktion übergibt, muß man nicht mehr als Rückgabewert wieder zurückgeben.
Präfixe wie user_ oder choosen_ sind überflüssig, weil sie dem Leser keinen Mehrwert bieten.
Code: Alles auswählen
from math import pi
def volume_cube(a):
return a ** 3
def volume_cuboid(a, b, c):
return a * b * c
def volume_bullet(radius):
return 4/3 * pi * radius ** 3
def volume_cylinder(radius, height):
return pi * radius ** 2 * height
def volume_cone(radius, height):
return pi * radius ** 2 * height / 3
def main():
print("Das ist ein Volumerechner.")
operation = input("Bitte wähle zuerst deinen Körper: 1 für Würfel, 2 für Quader, 3 für Kugel, "
"4 für Zylinder, 5 für Kegel: ")
if operation == "1":
a = float(input("Bitte gib die Länge der Seite a an: "))
digits = int(input("Bitte gib deine Nachkomastellen an: "))
volume = volume_cube(a)
print(f"Bei einer Seitenlänge von a = {a} ist das Volumen: {volume:.{digits}f}")
elif operation == "2":
a = float(input("Länge a eingeben: "))
b = float(input("Länge b eingeben: "))
c = float(input("Länge c eingeben: "))
digits = int(input("Nachkommastellen eingeben: "))
volume = volume_cuboid(a, b, c)
print(f"Bei a = {a} und b = {b} und c = {c} ist dein Volumen: {volume:.{digits}f}")
elif operation == "3":
radius = float(input("Bitte gib deinen gewünschten Radius ein: "))
digits = int(input("Bitte gib deine Nachkommastellen an: "))
volume = volume_bullet(radius)
print(f"Bei einem Radius von {radius} ist das Volumen: {volume:.{digits}f}"
f"\nIn der Formel wird für pi {pi} verwendet.")
elif operation == "4":
radius = float(input("Bitte gib deinen Radius ein: "))
height = float(input("Bitte gib deine Höhe ein: "))
digits = int(input("Bitte gib deine Nachkomastellen an: "))
volume = volume_cylinder(user_rad, user_height)
print(f"Bei einem Radius von {radius} und einer Höhe von {height} ist das Volumen {volume:.{digits}f}"
f"\nIn der Formel wird für pi = {pi} verwendet.")
elif operation == "5":
radius = float(input("Bitte gib deinen Radius ein: "))
height = float(input("Bitte gib deine Höhe ein: "))
digits = int(input("Bitte gib deine Nachkommastellen an: "))
volume = volume_cone(radius, height)
print(f"Bei einem Radius von {radius} und einer Höhe von {height} ist das Volumen: {volume:.{digits}f}"
f"\nIn der Formel wird für pi = {pi} verwendet.")
else:
print("keine gültige Eingabe.")
if __name__ == "__main__":
main()
“Absoluter” Mist nicht. Aber schon eine Menge.
Man definiert Funktionen nur dann nicht auf oberster Ebene, wenn sie “Closures” darstellen. Also Daten aus ihrer Umgebung benötigen, ohne die sie nicht funktionieren können. Das ist hier nicht der Fall. Es gibt keinerlei Grunde, die nicht alle einmal am Anfang zu definieren.
Wenn du mit “1” vergleichen willst, dann schreib das. Nicht str(1).
Strings werden mit Formatierung erzeugt. Nicht mit + zusammengestückelt.
Pi kommt aus dem Modul math. Und muss auch nicht zurückgegeben werden. Überhaupt gibt man nur das Ergebnis, und nicht nochmal alle Argumente einer Funktion zurück. Das können auch mehrere sein, aber Durchlaufen muss da keine.
Zur Eingabe sollte eine Funktion zur robusten Eingabe geschrieben werden, die bei Fehleingabe wieder neu auffordert, etwas einzugeben.
Es heißt chosen, nicht choosed. Die Eingaben für die verschiedenen Operationen sind auch nicht chosen, denn die kann man ja nicht auswählen.
Man definiert Funktionen nur dann nicht auf oberster Ebene, wenn sie “Closures” darstellen. Also Daten aus ihrer Umgebung benötigen, ohne die sie nicht funktionieren können. Das ist hier nicht der Fall. Es gibt keinerlei Grunde, die nicht alle einmal am Anfang zu definieren.
Wenn du mit “1” vergleichen willst, dann schreib das. Nicht str(1).
Strings werden mit Formatierung erzeugt. Nicht mit + zusammengestückelt.
Pi kommt aus dem Modul math. Und muss auch nicht zurückgegeben werden. Überhaupt gibt man nur das Ergebnis, und nicht nochmal alle Argumente einer Funktion zurück. Das können auch mehrere sein, aber Durchlaufen muss da keine.
Zur Eingabe sollte eine Funktion zur robusten Eingabe geschrieben werden, die bei Fehleingabe wieder neu auffordert, etwas einzugeben.
Es heißt chosen, nicht choosed. Die Eingaben für die verschiedenen Operationen sind auch nicht chosen, denn die kann man ja nicht auswählen.
Endlich mal eine sinnvolle Anwendung von Annotations:
Leider wurde das ja seit in Python 3.5 auf Type-Annotations eingeschränkt, also nicht benutzen.
Code: Alles auswählen
from math import pi
def volume_cube(a: "Seitenlänge") -> "Bei einer Seitenlänge von a = {a} ist das Volumen {volume:.{digits}f}":
return a ** 3
def volume_cuboid(a: "Länge a", b: "Länge b", c: "Länge c") -> "Bei a = {a} und b = {b} und c = {c} ist dein Volumen {volume:.{digits}f}":
return a * b * c
def volume_sphere(radius: "Radius") -> "Bei einem Radius von {radius} ist das Volumen: {volume:.{digits}f}":
return 4/3 * pi * radius ** 3
def volume_cylinder(radius: "Radius", height: "Höhe") -> "Bei einem Radius von {radius} und einer Höhe von {height} ist das Volumen {volume:.{digits}f}":
return pi * radius ** 2 * height
def volume_cone(radius: "Radius", height: "Höhe") -> "Bei einem Radius von {radius} und einer Höhe von {height} ist das Volumen: {volume:.{digits}f}":
return pi * radius ** 2 * height / 3
VOLUMES = {
"Würfel": volume_cube,
"Quader": volume_cuboid,
"Kugel": volume_sphere,
"Zylinder": volume_cylinder,
"Kegel": volume_cone,
}
def main():
print("Das ist ein Volumerechner.")
operation = int(input("Bitte wähle zuerst deinen Körper: {}: ".format(
", ".join(f"{nr} {name}" for nr, name in enumerate(VOLUMES, 1))
)))
function = list(VOLUMES.values())[operation]
arguments = {
key: float(input(f"{name}: "))
for key, name in function.__annotations__.items()
if key != "return"
}
digits = int(input("Bitte gib deine Nachkomastellen an: "))
volume = function(**arguments)
print(function.__annotations__["return"].format(volume=volume, digits=digits, **arguments))
if __name__ == "__main__":
main()
- __blackjack__
- User
- Beiträge: 14065
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Wobei ich persönlich da wohl mit `inspect.getfullargspec()` an die Annotationen rangehen würde statt direkt auf das magische Attribut zuzugreifen. Aber ja, schade das wir das jetzt nur noch für Typannotationen benutzen sollen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari