@CarlosDelgado: Das mag hart klingen, es sieht aber halt wirklich nicht aus wie Python sondern eher wie BASIC oder Pascal. Und das ist halt kein idiomatisches Python was man so schreiben würde wenn man wirklich in Python programmiert.
Bezüglich Begriffen: Listen sind keine Arrays. Es gibt auch Arrays, und damit meint man bei Python üblicherweise die Array-Datentypen aus dem Numpy-Package.
`Mitarbeiterliste` ist eine globale Variable → die darf es nicht geben. Und Grunddatentypen sollten nicht in Namen stehen, denn den Typ ändert man während der Entwicklung gar nicht so selten, oder es funktionieren auch andere Typen die sich gleich verhalten und dann hat man entweder verwirrende Namen im Quelltext stehen, oder man muss alle betroffenen Namen suchen und ändern, was unnötig Arbeit macht.
`isNotInList()` hat den falschen Namen oder macht das falsche. Wenn der Name stimmt, dann würde die Funktion `True` oder `False` zurückgeben. Wenn der Rückgabwert, die ID oder -1 stimmt, dann ist der Name falsch. Gehen wir mal davon aus, dass der Name falsch ist und der Rückgabwert richtig ist, dann ist der Name `index` an den das Ergebnis gebunden wird falsch, oder es ist der Rückgabewert falsch. Denn die ID ist kein Index. Es wird aber als Index in die Liste verwendet, was nur funktioniert wenn die ID immer dem Index entspricht. Was a) nicht wirklich garantiert ist, und b) die ID redundant machen würde, wenn Index und ID immer den gleichen Wert hätten.
Ich gehe mal davon aus, dass hier der Index gemeint ist, weil der Code der den Wert verwendet nur dann wirklich robust ist. Dann heisst `isNotInList()` eigentlich `get_index()`. Und statt einer magischen Zahl oder `None` sollte eine Ausnahme ausgelöst werden wenn kein Index gefunden werden kann.
`getImport()` ist als Name falsch. Da wird kein Import geholt, da wird ein Import durchgeführt.
Was bedeutet das `i` bei `ifile`? Kryptische Abkürzungen in Namen sollte man vermeiden.
`ifile` scheint kein Python-Datei(ähnliches) Objekt zu sein. Da ist `file` als Name ein bisschen verwirrend. Das scheinen eher Metainformationen *über* eine Datei zu sein‽
Was sollen die `l`-Präfixe bei den Einzelwerten von `file.order` bedeuten?
Von den ganzen Namen werden auch nur zwei tatsächlich verwendet, dann braucht man die nicht *alle* an Namen binden.
`readFile` ist als Name für einen Dateinamen falsch. Das klingt entweder nach einer Funktion die eine Datei liest, oder nach einer gelesenen Datei wenn man `read` als Vergangenheitsform betrachtet. Letztlich braucht man den Dateinamen aber auch gar nicht an einen zusätzlichen Namen binden der nur einmal und gleich in der nächsten Zeile verwendet wird. Und eine Zeichenkette ist das hoffentlich schon.
CSV-Dateien müssen für das `cvs`-Modul mit ``newline=""`` als Argument geöffnet werden — siehe Dokumentation. Und bei Textdateien sollte man immer explizit die Kodierung angeben, sonst kann man unangenehme Überraschungen erleben.
`line_count` wird sowohl im ``if``- als auch im ``else``-Zweig um 1 erhöht, also eigentlich immer, das kann also aus den beiden Zweigen raus und entweder vor oder hinter das ``if``/``else``-Konstrukt. Dann ist das ``if`` leer, also überflüssig. Und statt das manuell hoch zu zählen kann man das dann auch einfach mit `enumerate()` generieren.
Statt *in* der Schleife für jeden Datensatz zu prüfen ob der unter den anfänglich zu ignorierenden ist, würde man besser *vor* der Schleife die entsprechende Anzahl von Datensätzen überlesen.
`line_count` würde ich auch `row_count` nennen weil man dann besser sieht, dass das zu `row` gehört. Und im englischen ist auch ein Unterschied zwischen „line“ und „row“, und bei CSV-Dateien gilt nicht zwangsläufig „line“ (Zeile) = „row“ (Datensatz), denn ein Datensatz kann sich durchaus auch über mehr als eine Zeile erstrecken wenn man die Datei allgemein als Textdatei betrachtet.
`new_employees` kann man sich im Grunde sparen, denn das ist ja die Länge der lokalen `mitarbeiter`-Liste. *Die* sollte `new_employees` heissen, damit man da nicht so ein komisches Denglisch in den Namen hat.
Und am Ende sollte man dann `mitarbeiter` zurückgeben, denn sonst macht das ja keinen Sinn da eine Liste für zu füllen die nirgends verwendet.
Die Funktion verwendet `DiffFile` aus dem nichts, das muss ein Argument sein. Ausser es ist ein Dateiname und eine Konstante, dann ist es aber falsch benannt (Datei ≠ Dateiname), und falsch geschrieben weil Konstanten KOMPLETT_GROSS geschrieben werden, damit man sie als solche erkennen kann.
Zeichenketten und Werte mit `str()` und ``+`` zusammenstückeln ist eher BASIC denn Python. In Python gibt es dafür die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.
Ungetestet:
Code: Alles auswählen
from itertools import islice
def get_index(firstname, lastname, employees):
try:
return next(
index
for index, employee in enumerate(employees)
if (employee.firstname, employee.lastname) == (firstname, lastname)
)
except StopIteration:
raise ValueError("no employee found")
def import_employees(file_info, employees, diff_file):
new_employees = []
_, firstname_key, lastname_key, *_ = file_info.order
with open(file_info.name, encoding="utf-8", newline="") as csv_file:
numbered_rows = enumerate(csv.reader(csv_file, delimiter=";"), 1)
updated_employees_count = 0
row_count = 0
for row_count, row in islice(numbered_rows, file_info.offset, None):
try:
index = get_index(
row[firstname_key], row[lastname_key], employees
)
except ValueError:
employee = create_employee_from_row(
row, file_info.order, file_info.time
)
new_employees.append(employee)
write_object_to_file(employee, diff_file)
else:
update_employee(row, index, len(new_employees), file_info)
updated_employees_count += 1
print(f"Imported: {row_count} lines from {file_info.name}")
print(f"New employees: {len(new_employees)}")
print(f"Updated employees: {updated_employees_count}")
return new_employees