@remboven: Importe gehören normalerweise an den Anfang eines Moduls. In jeder Funktion Module zu importieren ist unübersichtlich. Man kann dann nicht mal eben schnell schauen von welchen anderen Modulen das Modul abhängt.
Programmlogik und Benutzerinteraktion ist überhaupt nicht getrennt. Man könnte von dem Programm so zum Beispiel nichts wiederverwenden, wenn man eine GUI für die Rechnungsverwaltung schreiben möchte.
``return`` und ``except`` sind keine Funktionen, die sollte man also auch nicht wie welche hinschreiben. Also ohne Klammern.
`select_customer()` ist deutlich zu kompliziert. Ein Dictionary mit fortlaufenden Zahlen als Schlüssel ist eigentlich eine Liste. `keys` wird nicht verwendet, also könnte man die erste Zeile einfach vor der Schleife überlesen, statt mit dem manuell hochgezählten `x` zu arbeiten. Wenn man einen Index neben den eigentlichen Elementen eines "Iterable" benötigt, bietet sich die `enumerate()`-Funktion an.
Dateien die man öffnet, sollte man auch explizit wieder schliessen, oder die ``with``-Anweisung dafür verwenden.
Die `select_customer()`-Funktion könnte so aussehen (ungetestet und immer noch Logik und Benutzerinteraktion gemischt):
Code: Alles auswählen
def select_customer(filename):
with open(filename) as reader:
next(reader) # Skip keys.
customers = list(reader)
for i, customer in customers:
print('[%d] %s' % (i, customer)
return customers[int(input("Welchen Kunden möchten Sie auswählen? "))]
Du scheinst das Programm nicht getestet zu haben, denn in `add_entry()` wird eine Funktion `reader()` aufgerufen, die nirgends definiert ist!?
Endlosrekursion um das Hauptprogramm erneut aufzurufen ist keine gute Idee, weil man damit ein Speicherleck hat und das Programm mit einer Aussnahme aussteigt, wenn das Rekursionslimit erreicht ist, oder bei anderen Implementierungen als CPython vielleicht sogar hart abstürzt, wenn der Stapelspeicher "voll" ist und zum Beispiel anfängt den Datenbereich des Programms zu überschreiben.
Die erste Zuweisung an `travel_cost` in `create_bill()` wird nirgends verwendet. Die Unterscheidung ob `duration` gleich 1 ist, kannst Du Dir sparen. Beim ``else``-Teil würde nämlich das selbe heraus kommen. Beim zweiten mal ist der ``if``-Teil überflüssig, denn die Zeile für die erste Stunde hängt ja gar nicht von der `duration` ab, die kommt in beiden Zweigen vor. Und damit kann sie ohne Bedingung davor gezogen werden. Die zweite Zeile hängt davon ab ob `duration` grösser als 1 ist.
Das Runden auf zwei Stellen mit `round()` funktioniert so nicht zuverlässig und macht bei Python 3.x vielleicht auch nicht das, was Du erwartest. Da sollte man eventuell mit dem `decimal`-Modul arbeiten.
Die ganzen `str()`-Aufrufe beim Formatieren der Zahlen sind überflüssig. Der ``%``-Operator liefert hier ja schon ein Objekt vom Typ `str`.
Die vielen `bill.replace()`-Aufrufe sollte man durch ein Template-System ersetzen. `string.Template` aus der Standardbibliothek bietet sich an, wenn man keine externe Abhängigkeit haben möchte.
`mark_as_payed()` dürfte Probleme bekommen, wenn es für einen Kunden mehr als eine Rechnung gibt.