Hallo,
ich habe nur mal eine logische Frage. Ich habe das folgende Video gesehen: https://www.youtube.com/watch?v=IgzDB-FJDL0
Minute 20:28 und 24:28 im Vergleich betrachtet.
Um Daten in eine Excel Tabelle zu schreiben, kann man ja anscheinend das ganze in ["B2"] machen oder wenn man die ganze Spalte die Formel erweitern will mit einer for schleife.
Jedoch wird die Variable dann mit einen + hinter den Spalten Buchstaben geschrieben statt mit in die " " rein, das find ich logisch nicht ganz nachvollziehbar da ja die Variable als Zahlersatz hier dienen soll. Gibt es dafür eine Erklärung oder ist es einfach so...
Basic for Schleife mit Excel Zellbezug
- noisefloor
- User
- Beiträge: 4272
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
bitte mal den relevanten Code hier in einen Codeblock posten. Und noch sagen, welches Python-Modul zur Interaktion mit Excel verwendest. OOTB kann Python das nicht und es gibt mehrere Module für Excel.
Gruß, noisefloor
bitte mal den relevanten Code hier in einen Codeblock posten. Und noch sagen, welches Python-Modul zur Interaktion mit Excel verwendest. OOTB kann Python das nicht und es gibt mehrere Module für Excel.
Gruß, noisefloor
- __blackjack__
- User
- Beiträge: 14259
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@hellooo: Ich verstehe die Frage nicht. Wenn man auf eine Zelle in einem Arbeitsblatt über die Koordinaten in Excelschreibweise zugreifen will dann sind das Buchstaben für die Spaltenangabe gefolgt von Ziffern für die Zeilenangabe, also aus Python-Sicht eine Zeichenkette/Text. Wenn man die Zeilennummer als Zahl vorliegen hat, dann muss man eine Zeichenkette erstellen in dem man die Spalten und Zeileninformation entsprechend zusammenfügt. Also den (oder die) Buchstaben mit der Zahl als Zeichenkette verbinden.
Im Videotutorial wird das auf eine eher „unpythonische“ weise gemacht mit `str()` und ``+``. Das ist eher BASIC denn Python. In Python macht man so etwas mit Zeichenkettenformatierung mit f-Zeichenketten. Oder falls die Vorlage dynamisch sein soll mit der `format()`-Methode auf Zeichenketten. Also konkret statt so etwas wie ``"C" + str(row)`` schreibt man in Python ``f"C{row}"``. Und statt `row` würde ich das auch eher `row_number` nennen, denn es ist ja keine Zeile sondern eine Zeilennummer. Eine Liste mit Werten oder Zellen für eine Zeile kann man ja auch als Wert haben und da ist `row` dann ein passender Name.
Was an dem Tutorial auch schlecht ist, ist die Namenswahl. Zum einen dauernd kryptische Abkürzungen, und dann auch ”technisch” korrekte, aber total nichtssagende Namen. Beispielsweise die Variablen `c2` und `d2` für die Zellenwerte von C2 und D2 im Arbeitsblatt. Ja das sind irgendwie korrekte Namen, aber komplett Unsinnig wenn es darum geht zu verstehen was das Programm macht. Der Leser vom Quelltext will ja nicht wissen aus welchen Zellen die Werte kommen, sondern was die Werte in diesen Zellen *bedeuten*. Im Arbeitsblatt „Bestellungen“ wären das zum Beispiel `anzahl` und `preis`.
Um die Schleife erweitert und mit f-Zeichenketten statt `str()` und ``+``:
Dieses manuelle Zusammenbasteln von Excel-Zellenkoordinaten ist aber gar nicht nötig. Man kann auch Zeilenweise über die Zellen eines rechteckigen Ausschnitts in einer Schleife iterieren, in dem man für Zeilen und Spalten jeweils Start und Ende als Zeilen und Spaltennummern an die `iter_rows()`-Methode übergibt:
Im Tutorial werden die Begriffe Array und Liste vermischt. Das ist nicht gut. Der Grunddatentyp der verwendet wird ist eine Liste. Es gibt auch Arrays in Python, womit in der Regel Numpy-Arrays gemeint sind. Das sollte man nicht durcheinander bringen.
Die `get_price()`-Funktion greift einfach so magisch auf das `Workbook`-Objekt zu. Das sollte nicht sein. Funktionen sollten in sich geschlossen sein, und alles was sie ausser Konstanten benötigen als Argument(e) übergeben bekommen. Globale Variablen sollten eigentlich gar nicht existieren, weshalb man das Hauptprogramm auch in eine Funktion steckt. Die heisst in der Regel `main()`.
Statt so einen komischen Wert wie 9999999 zurück zu geben, falls der Produktname nicht gefunden werden konnte, würde man eine Ausnahme auslösen. Darum kann sich der Aufrufer dann explizit kümmern und selber entscheiden was genau passieren soll. Oder man kümmert sich nicht explizit darum und lässt das Programm dann durch den Fehler abbrechen. Das Programm könnte dann so aussehen:
Die beiden Schleifen könnte man zu einer Schleife zusammenfassen:
Das lineare Suchen in der Preisliste ist ineffizient. Da würde man besser die Daten aus der Preisliste in ein Wörterbuch (Datentyp `dict`) überführen:
Im Videotutorial wird das auf eine eher „unpythonische“ weise gemacht mit `str()` und ``+``. Das ist eher BASIC denn Python. In Python macht man so etwas mit Zeichenkettenformatierung mit f-Zeichenketten. Oder falls die Vorlage dynamisch sein soll mit der `format()`-Methode auf Zeichenketten. Also konkret statt so etwas wie ``"C" + str(row)`` schreibt man in Python ``f"C{row}"``. Und statt `row` würde ich das auch eher `row_number` nennen, denn es ist ja keine Zeile sondern eine Zeilennummer. Eine Liste mit Werten oder Zellen für eine Zeile kann man ja auch als Wert haben und da ist `row` dann ein passender Name.
Was an dem Tutorial auch schlecht ist, ist die Namenswahl. Zum einen dauernd kryptische Abkürzungen, und dann auch ”technisch” korrekte, aber total nichtssagende Namen. Beispielsweise die Variablen `c2` und `d2` für die Zellenwerte von C2 und D2 im Arbeitsblatt. Ja das sind irgendwie korrekte Namen, aber komplett Unsinnig wenn es darum geht zu verstehen was das Programm macht. Der Leser vom Quelltext will ja nicht wissen aus welchen Zellen die Werte kommen, sondern was die Werte in diesen Zellen *bedeuten*. Im Arbeitsblatt „Bestellungen“ wären das zum Beispiel `anzahl` und `preis`.
Code: Alles auswählen
#!/usr/bin/env python3
from openpyxl import load_workbook
def main():
filename = "Bestellungen.xlsx"
workbook = load_workbook(filename)
sheet = workbook["Bestellungen"]
count = sheet["C2"].value
price = sheet["D2"].value
total = count * price
print("Preis ist:", total)
sheet["E2"].value = total
workbook.save(filename)
if __name__ == "__main__":
main()Code: Alles auswählen
#!/usr/bin/env python3
from openpyxl import load_workbook
def main():
filename = "Bestellungen.xlsx"
workbook = load_workbook(filename)
sheet = workbook["Bestellungen"]
for row_number in range(2, 23):
count = sheet[f"C{row_number}"].value
price = sheet[f"D{row_number}"].value
sheet[f"E{row_number}"].value = count * price
workbook.save(filename)
if __name__ == "__main__":
main()Code: Alles auswählen
#!/usr/bin/env python3
from openpyxl import load_workbook
def main():
filename = "Bestellungen.xlsx"
workbook = load_workbook(filename)
sheet = workbook["Bestellungen"]
for count_cell, price_cell, total_cell in sheet.iter_rows(2, 22, 3, 5):
total_cell.value = count_cell.value * price_cell.value
workbook.save(filename)
if __name__ == "__main__":
main()Die `get_price()`-Funktion greift einfach so magisch auf das `Workbook`-Objekt zu. Das sollte nicht sein. Funktionen sollten in sich geschlossen sein, und alles was sie ausser Konstanten benötigen als Argument(e) übergeben bekommen. Globale Variablen sollten eigentlich gar nicht existieren, weshalb man das Hauptprogramm auch in eine Funktion steckt. Die heisst in der Regel `main()`.
Statt so einen komischen Wert wie 9999999 zurück zu geben, falls der Produktname nicht gefunden werden konnte, würde man eine Ausnahme auslösen. Darum kann sich der Aufrufer dann explizit kümmern und selber entscheiden was genau passieren soll. Oder man kümmert sich nicht explizit darum und lässt das Programm dann durch den Fehler abbrechen. Das Programm könnte dann so aussehen:
Code: Alles auswählen
#!/usr/bin/env python3
from openpyxl import load_workbook
def get_price(sheet, name):
for product_name, price in sheet.iter_rows(2, 11, 1, 2, values_only=True):
if product_name == name:
return price
raise KeyError(f"no price for {name}")
def main():
filename = "Bestellungen.xlsx"
workbook = load_workbook(filename)
order_sheet = workbook["Bestellungen"]
#
# Preise in Tabelle ausfüllen.
#
price_sheet = workbook["Preisliste"]
for product_name_cell, _, price_cell in order_sheet.iter_rows(2, 22, 2, 4):
price_cell.value = get_price(price_sheet, product_name_cell.value)
#
# Gesamtpreis für Bestellungen berechnen.
#
for count_cell, price_cell, total_cell in order_sheet.iter_rows(
2, 22, 3, 5
):
total_cell.value = count_cell.value * price_cell.value
workbook.save(filename)
if __name__ == "__main__":
main()Code: Alles auswählen
#!/usr/bin/env python3
from openpyxl import load_workbook
def get_price(sheet, name):
for product_name, price in sheet.iter_rows(2, 11, 1, 2, values_only=True):
if product_name == name:
return price
raise KeyError(f"no price for {name}")
def main():
filename = "Bestellungen.xlsx"
workbook = load_workbook(filename)
order_sheet = workbook["Bestellungen"]
price_sheet = workbook["Preisliste"]
for (
product_name_cell,
count_cell,
price_cell,
total_cell,
) in order_sheet.iter_rows(2, 22, 2, 5):
price_cell.value = get_price(price_sheet, product_name_cell.value)
total_cell.value = count_cell.value * price_cell.value
workbook.save(filename)
if __name__ == "__main__":
main()Code: Alles auswählen
#!/usr/bin/env python3
from openpyxl import load_workbook
def main():
filename = "Bestellungen.xlsx"
workbook = load_workbook(filename)
product_name_to_price = dict(
workbook["Preisliste"].iter_rows(2, 11, 1, 2, values_only=True)
)
for (
product_name_cell,
count_cell,
price_cell,
total_cell,
) in workbook["Bestellungen"].iter_rows(2, 22, 2, 5):
price_cell.value = product_name_to_price[product_name_cell.value]
total_cell.value = count_cell.value * price_cell.value
workbook.save(filename)
if __name__ == "__main__":
main()“Programming is partially an artform and, like artists, programmers will do it even if they don't get money.” — Linus Torvalds
- DeaD_EyE
- User
- Beiträge: 1308
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Alternativ kann man auch den slice-Syntax verwenden.
Hier ein Beispiel, wo über einen Bereich von A1 - C3 iteriert wird.
Alternativ kann man auch nur einen str verwenden:
Das funktioniert beides, da Worksheet.__getitem__ aus dem slice-Objekt wieder einen str erstellt. Das wird dann intern verarbeitet. Erst holt er sich über eine andere Funktion die Grenzen und dann wird die Methode iter_rows verwendet.
Hier ein Beispiel, wo über einen Bereich von A1 - C3 iteriert wird.
Code: Alles auswählen
doc = openpyxl.load_workbook("example.xlsx")
# 1. Arbeitsblatt
ws = doc.worksheets[0]
for row in ws["A1":"C3"]:
print(row)
Code: Alles auswählen
ws["A1:C3"]sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
