@Sirius3, habe ein paar Parameter in Deinem neuen auf BlackJacks basierendem code angepasst und nun läuft er durch. Ich musste numpy wieder hinzunehmen, weil er zip-Objekte nicht in com Umgebungen konvertieren kann. Code ist jetzt mit Faktor 3 schneller im Vergleich zu Deiner originären Variante. Ich vermute, dass ist viel performanter, weil die Infos direkt aus der geöffneten Datei (ohne Openpyxl) geholt werden. ist jetzt wirklich sehr performant!
Hier noch der letzte code von BlackJack.
Code: Alles auswählen
#!/usr/bin/env python3
from contextlib import closing
import numpy as np
import win32com.client as com
from attr import attrib, attrs
from openpyxl import load_workbook
from openpyxl.utils import column_index_from_string
import time
zeit_anf = time.time()
@attrs
class Vertrag:
ab = attrib()
bis = attrib()
betrag = attrib()
rentenzeichen = attrib()
zahltermine_pro_jahr = attrib()
gruppe = attrib()
@property
def monat(self):
return 0 if self.ab is None else self.ab.month
def ist_faellig_am(self, datum):
return (
(datum.month + 12 - self.monat) % (12/self.zahltermine_pro_jahr) == 0
and (not self.ab or self.ab <= datum)
and (not self.bis or datum < self.bis)
)
def lese_vertraege(sheet):
return [
Vertrag(
vertrag_ab,
None if verlaengern_text == "verlängern" else vertrag_bis,
betrag,
rentenzeichen,
zahltermine_pro_jahr,
gruppe,
)
for (
rentenzeichen,
betrag,
_,
_,
vertrag_ab,
vertrag_bis,
verlaengern_text,
zahltermine_pro_jahr,
gruppe,
) in sheet.iter_rows(
98,
121,
column_index_from_string("J"),
column_index_from_string("R"),
values_only=True,
)
]
def lese_monate(sheet):
headers = next(sheet.iter_rows(1, 1, 1, 100, values_only=True))
return next(
sheet.iter_rows(
97,
97,
headers.index("Änderungsdatum") + 2,
headers.index("letzte") + 1,
values_only=True,
)
)
def lade_vertraege(filename):
with closing(load_workbook(filename)) as workbook:
sheet = workbook["Vertraege"]
column_index = column_index_from_string("R")
return (
lese_vertraege(sheet),
lese_monate(sheet),
list(
sheet.iter_cols(
column_index, column_index, 54, 57, values_only=True
)
),
)
def summiere_vertraege(vertraege, datum, gruppe, rentenzeichen):
summe = 0
summe_renten = 0
for vertrag in vertraege:
if vertrag.ist_faellig_am(datum) and vertrag.gruppe == gruppe:
summe += vertrag.betrag
if vertrag.rentenzeichen == rentenzeichen:
summe_renten += vertrag.betrag
return summe, summe_renten
def main():
vertraege, monate, gruppen = lade_vertraege(
R"C:\Users\Jan\Desktop\Python\python.xlsm"
)
sheet = com.Dispatch("Excel.Application").ActiveSheet
rentenzeichen = sheet.Range("L71").Value
neue_daten = []
renten_gesamt = []
for datum in monate:
summen = []
renten_monat = []
#print(gruppen)
for gruppe in gruppen:
#print(gruppe)
summe, summe_renten = summiere_vertraege(
vertraege, datum, gruppe, rentenzeichen
)
summen.append(summe)
renten_monat.append(summe_renten)
neue_daten.append(summen)
renten_gesamt.append(renten_monat)
# data_rows in den ausgewählten Bereich schreiben:
#sheet.Range("R54:R57").Value = [[g] for g in gruppen]
sheet.Range(sheet.Range("S2").Value).Value = np.array(neue_daten).T
sheet.Range("U63:CB63").Value = np.array(renten_gesamt).T
zeit_end = time.time()
sheet.Range("Q47").Value = zeit_end - zeit_anf
print (zeit_end - zeit_anf)
if __name__ == "__main__":
main()
Ich hatte ihn noch nicht auf die Version ohne openpyxl angepasst, da ich erst sicherstellen wollte, dass er saubere Werte generiert. Der entscheidende Unterschied zu Deiner Variante ist die Generierung der Gruppen. Blackjack erstellt in lade_vertraege eine Liste, die sich im output durch eine zusätzliche öffnende / schliessende (Rund)klammer von Deiner Gruppenliste unterscheidet. Und dadurch wird wie beschrieben beim Schleifendurchlauf nicht gegen eine Gruppe aus der Liste , sondern immer gegen die gesamte Liste gematcht, was bewirkt, dass nie die Bedingung "Gruppe des Schleifendurchlaufs == Gruppe" passt. Damit läuft Blackjacks code zwar sauber und schnell durch, aber generiert nur Nullwerte (weil keine erfüllte Bedingung).
Mich interessiert der Unterschied eigentlich nur noch zum Lernen (warum klappt es mit der einen Methode und der anderen nicht?). Prozessual bin ich mit dem aktuellen Stand sehr zufrieden.