@mechanicalStore: Weil ist halt so. `print()` ruft intern `str()` auf. Die `write()`-Methode geht davon aus, das man die Daten vom passenden Typ übergibt.
Den Präfix `my`/`My` vergisst Du am besten gleich wieder, denn der macht keinen Sinn wenn es nicht auch ein `their` oder `our` gibt gegen den sich das abgrenzen würde.
Grundatentypen haben nichts in Namen verloren. Während der Entwicklung ändert sich das gerne mal und dann hat man entweder falsche irreführende Namen oder muss überall alle von der Änderung betroffenen Namen anpassen.
Namen sollten keine kryptischen Abkürzungen enthalten. Zum Beispiel `pr_` — da habe ich keine Ahnung wofür das stehen soll.
`FILE_PRAEFIX` sollte wohl `FILE_SUFFIX` heissen.
Man verwendet keine globalen Variablen. Klassenattribute sind in der Regel deshalb nur Konstanten. Eine dynamische Liste mit Objekten hat dort nichts zu suchen. Das passt auch gar nicht zur Aufgabe einer Klasse für *einen* Eintrag da alle Einträge zu verwalten. `save_entries()` wird damit zu einer Funktion welche die Einträge als Argument bekommt und `create_entry()` würde den erzeugten Eintrag als Ergebnis liefern statt eine globale Liste zu erweitern. In `create_entry()` kann man auch das `entry()` weglassen, denn das ist ja schon klar weil das auf dem Typ `Entry` aufgerufen wird.
`create_entry()` ist fehlerhaft weil `now()` mehrfach aufgerufen wird, zwischen diesen Aufrufen ja aber Zeit vergeht, also am Ende Datum und Uhr(zeiten) nicht zusammen passen, beispielsweise wenn der Aufruf für das Datum vor Mitternacht, mindestens einer der Aufrufe für die Uhrzeit aber nach Mitternacht passiert. Wenn man einen Zeitpunkt haben will, dann darf man dafür immer nur *einen* Aufruf machen, auch wenn man die Daten dann auf mehrere Variablen aufteilen möchte.
Die Methode ist auch nicht wirklich notwendig, weil man das auch in die `__init__()` schreiben kann.
Es fehlen Fehlerbehandlungen für den Fall das `project` ein "|" oder ein "\n" enthält oder `start` grösser als `end` ist.
Beim schreiben der Einträge fehlt ein Trenner für die Datensätze, also beispielsweise ein "\n".
Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.
Zwischenstand:
Code: Alles auswählen
#!/usr/bin/env python3
from datetime import datetime
FILENAME_SUFFIX = ".txt"
class Entry:
DELIMITER = "|"
def __init__(self, project, date=None, start=None, stop=None):
for illegal_character in [self.DELIMITER, "\n"]:
if illegal_character in project:
raise ValueError(
f"`project` contains illegal character"
f" ({illegal_character!r})"
)
if None in [date, start, stop]:
now = datetime.now()
if date is None:
date = format(now, "%Y-%m-%d")
if start is None:
start = format(now, "%H:%M:%S")
if stop is None:
stop = format(now, "%H:%M:%S")
if start > stop:
raise ValueError(f"start ({start!r}) > stop ({stop!r})")
self.project = project
self.date = date
self.start = start
self.stop = stop
def __repr__(self):
return (
f"{self.__class__.__name__}"
f"({self.project!r}, {self.date!r}, {self.start!r}, {self.stop!r})"
)
def __str__(self):
return self.DELIMITER.join(
[self.project, self.date, self.start, self.stop]
)
@classmethod
def parse(cls, text):
return cls(*text.rstrip().split(cls.DELIMITER))
def save_entries(entries, filename):
with open(filename + FILENAME_SUFFIX, "w", encoding="utf-8") as file:
file.writelines(f"{entry}\n" for entry in entries)
def load_entries(filename):
with open(filename + FILENAME_SUFFIX, "r", encoding="utf-8") as lines:
return list(map(Entry.parse, lines))
def main():
entries = [Entry(f"P-21-001-{index}") for index in range(5)]
save_entries(entries, "test")
print("Wrote file...")
print(load_entries("test"))
if __name__ == "__main__":
main()
Ich würde die Daten im `Entry` nicht als Zeichenkette speichern sondern als `datetime.date` und `datetime.time`-Objekte und nur zur Aus- und Eingabe in Zeichenketten wandeln beziehungsweise aus Zeichenketten parsen. Denn irgendwann wird man damit auch mal rechnen wollen, und dann wird es hässlich mit Umwandlungscode jedes mal wenn man irgendwo rechnen will/muss.
(De)serialisieren würde ich auch nicht in dem `Entry`-Objekt machen sondern in den Lade-/Speicherfunktionen. Und da dann auch weniger selber basteln, sondern etwas wie JSON(-Lines) oder CSV verwenden. Dann kann auch `project` alles enthalten was in einem Dateiformat eventuell eine besondere Bedeutung hätte. Man braucht das dann nicht mehr prüfen, und die Bibliothek zum Lesen und Schreiben des Datenformats kümmert sich um die Sonderbehandlung.