Seite 1 von 2
TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 15:41
von Master_Shredder
Hallo,
ich habe hier eine Funktion zeitspanne_ermitteln(...) sie nimmt Parameter entgegen und soll mir ermitteln wie viel Tage oder Monate VON BIS sind.
Code: Alles auswählen
def zeitspanne_ermitteln(
self,
vonJJJJ: int,
vonM: int,
vonT: int,
bisJJJJ: int,
bisM: int,
bisT: int,
einheit: str,
):
if bisJJJJ == 0 and bisM == 0 and bisT == 0:
zeitspanne = datetime.now() - datetime(vonJJJJ, vonM, vonT)
else:
zeitspanne = datetime(bisJJJJ, bisM, bisT) - datetime(vonJJJJ, vonM, vonT)
zeitspanne = zeitspanne.total_seconds()
if einheit == "Tage":
tage = zeitspanne / 86400
return tage
elif einheit == "Monate":
monate = math.floor(zeitspanne / 2419200) + 1
return monate
Dann habe ich 2 Proberty Variablen die darauf zugreifen.
die Erste funktioniert wunderbar die Zweite irgendwie nicht. Obwohl sie fast identisch sind?
Als Fehlermeldung bekomme ich:
Code: Alles auswählen
/usr/bin/python3.12 /home/masterblack/PycharmProjects/Verbrauchsrechner/verbrauchsrechner.py
Traceback (most recent call last):
File "/home/masterblack/PycharmProjects/Verbrauchsrechner/verbrauchsrechner.py", line 43, in berechne
f"{abrechnung.bisheriger_gezahlter_abschlag:.2f} €"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/masterblack/PycharmProjects/Verbrauchsrechner/berechnungen/abrechnung.py", line 80, in bisheriger_gezahlter_abschlag
betrag = monate * self.tarif.monatlicher_abschlag
~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'
Code: Alles auswählen
@property
def grundpreis_tagesgenau_netto(self) -> float:
"""
Ermittlung des Grundpreises bis zum heutigen Tag netto
Returns
-------
float
"""
betrag_tag = self.nettobetrag_berechnen(self.tarif.grundpreis) * 12 / 365
tage = self.zeitspanne_ermitteln(2024, 6, 13, 0, 0, 0, "Tage")
betrag = round(betrag_tag * tage, 3)
return betrag
@property
def bisheriger_gezahlter_abschlag(self):
monate = self.zeitspanne_ermitteln(2024, 6, 1, 0, 0, 0, "Monat")
betrag = monate * self.tarif.monatlicher_abschlag
return betrag
Re: TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 16:05
von juwido
keine Ahnung ob es das schon ist, aber unten wird als Einheit "Monat" übergeben, oben aber auf "Monate" geprüft...
Re: TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 16:07
von __blackjack__
@Master_Shredder: `zeitspanne_ermitteln()` gibt `None` zurück in `bisheriger_gezahlter_abschlag()`. Hättest Du den Rückgabetyp von `zeitspanne_ermitteln()` annotiert, hätte Dich die Typprüfung darauf hingewiesen.
Wenn man ein ``if``/``elif``-Konstrukt hat, sollte man immer überlegen warum da kein ``else`` ist und eines hinschreiben was einen Fehler auslöst wenn der Fall eigentlich nicht vorkommen sollte. Denn wenn man Fehler macht, passiert es halt doch.
Re: TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 16:33
von Master_Shredder
juwido hat geschrieben: Dienstag 15. Oktober 2024, 16:05
keine Ahnung ob es das schon ist, aber unten wird als Einheit "Monat" übergeben, oben aber auf "Monate" geprüft...
OH MY GOD

Ja das war es. Ja ich war irgendwie so den TypeError am suchen, dass ich gar nicht an einen anderen Fehler gedacht habe.
Dankeschön
...sollte man immer überlegen warum da kein ``else`` ist und eines hinschreiben...
Ah ja, stimmt!
Danke
Re: TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 16:50
von narpfel
Wenn man schon Typannotationen benutzt, sollte man sie auch
richtig benutzen:
Code: Alles auswählen
from datetime import datetime
from typing import Literal
from typing import assert_never
type Einheit = Literal["Tage", "Monate"]
def zeitspanne_ermitteln(
vonJJJJ: int,
vonM: int,
vonT: int,
bisJJJJ: int,
bisM: int,
bisT: int,
einheit: Einheit,
) -> float:
if bisJJJJ == 0 and bisM == 0 and bisT == 0:
zeitspanne = datetime.now() - datetime(vonJJJJ, vonM, vonT)
else:
zeitspanne = datetime(bisJJJJ, bisM, bisT) - datetime(vonJJJJ, vonM, vonT)
match einheit:
case "Tage":
return zeitspanne.total_seconds() / 86_400
case "Monate":
return zeitspanne.total_seconds() // 2_419_200 + 1
case _:
assert_never(einheit)
def main() -> None:
zeitspanne_ermitteln(1234, 5, 6, 1235, 6, 7, "Monate")
zeitspanne_ermitteln(1234, 5, 6, 1235, 6, 7, "Monat")
if __name__ == "__main__":
main()
Code: Alles auswählen
$ mypy --strict t.py
t.py:32: error: Argument 7 to "zeitspanne_ermitteln" has incompatible type "Literal['Monat']"; expected "Literal['Tage', 'Monate']" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Zwei Vorteile mit `Literal["Tage", "Monate"]` und `match`: `mypy` kann überprüfen, dass man nichts falsches übergibt, und es kann überprüfen, dass man alle Möglichkeiten im `match` beachtet hat.
Oder man benutzt `enum.Enum`, damit hat man die gleichen Vorteile, aber ein bisschen mehr Tipparbeit.
Re: TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 16:59
von __blackjack__
Also mir gefällt die API der Funktion nicht. Weder bei den Argumenten 1 oder 2 Datumsangaben als einzelne Zahlen statt als `date`-Objekte und die zweite Angabe ist ”optional” in dem man da drei Argumente mit dem Wert 0 übergibt. Und eine Funktion die über ein Zeichenketten-Argument entscheidet in welcher ”Einheit” das eigentlich gleiche Ergebnis zurückgegeben wird, ist auch nicht gut. Zumal die Werte nicht wirklich gleichwertig sind, denn aus den Monaten kann man nicht die Tage errechnen. An der Stelle müsste man sowieso mal dokumentieren was „ein Monat“ hier eigentlich bedeutet. Monate sind ja nicht gleich lang. Tage auch nicht unbedingt (Schaltjahre und -sekunden).
Und der Funktionsname ist falsch. Eine Zeitspanne hat einen Anfang und ein Ende. Was hier ausgerechnet wird ist eine Dauer oder die *Länge* einer Zeitspanne.
Re: TypeError: unsupported operand type(s)
Verfasst: Dienstag 15. Oktober 2024, 19:26
von Sirius3
@Master_Shredder: Variablennamen sollten sinnvoll benannt sein und werden komplett klein geschrieben. Was bedeutet JJJJ?
Warum gibt es Bruchteile von Tage aber keine Burchteile von Monaten? Warum ist bei einer Zeitspanne von exakt einem Monat das Resultat 2?
Wenn `self` in einer Funktion gar nicht benutzt wird, ist das ein Alarmsignal, dass man in Wirklichkeit gar keine Klasse hat.
Statt literale Strings benutzt man am besten ein Enum, das vermeidet Schreibfehler.
Code: Alles auswählen
class ZeitEinheit(enum.Enum):
Tage=Enum.auto()
Monate=Enum.auto()
def zeitspanne_ermitteln(start_datum, end_datum=None, einheit=ZeitEinheit.Tage):
start_datum = datetime(*start_datum)
end_datum = datetime.now() if end_datum is None else datetime(*end_datum)
zeitspanne = (end_datum - start_datum).total_seconds() / (60*60*24)
if einheit == ZeitEinheit.Tage:
return zeitspanne
elif einheit == ZeitEinheit.Monate:
return zeitspanne / 28
else:
raise ValueError("einheit")
Re: TypeError: unsupported operand type(s)
Verfasst: Mittwoch 16. Oktober 2024, 14:46
von Master_Shredder
@narpfel Ah, eine match-Anweisung. Da bin ich dabei

.
Nur was bedeutet den diese Schreibweise, mit Underscores bei den Tausendertrennzeichen? 2_419_200
Und warum sind hier zwei // (Slashes) hat dies vielleicht etwas damit zu tun, dass ich nicht mehr ausklammern muss?
Weder bei den Argumenten 1 oder 2 Datumsangaben als einzelne Zahlen statt als `date`-Objekte und die zweite Angabe ist ”optional” in dem man da drei Argumente mit dem Wert 0 übergibt.
Ja OK bin für Verbesserungen offen. Nur wie soll ich den "date" Objekte übergeben. Und wie soll ich entscheiden lassen was nun verwendet werden soll?
Re: TypeError: unsupported operand type(s)
Verfasst: Mittwoch 16. Oktober 2024, 17:23
von snafu
Master_Shredder hat geschrieben: Mittwoch 16. Oktober 2024, 14:46
Nur was bedeutet den diese Schreibweise, mit Underscores bei den Tausendertrennzeichen? 2_419_200
Das ist zur Vereinfachung von größere Zahlenangaben gedacht. Die Unterstriche werden von Python ignoriert und sollen einfach nur dem menschlichen Leser helfen. Das hätte man übrigens auch selber ausprobieren können.
Master_Shredder hat geschrieben: Mittwoch 16. Oktober 2024, 14:46
Und warum sind hier zwei // (Slashes) hat dies vielleicht etwas damit zu tun, dass ich nicht mehr ausklammern muss?
Mit den beiden Slashes sorgt man für eine ganzzahlige Division. Es kommt beim Ergebnis also immer ein Integer raus. Auch hier gilt mein Kommentar zum Thema DIY.
Master_Shredder hat geschrieben: Mittwoch 16. Oktober 2024, 14:46
Ja OK bin für Verbesserungen offen. Nur wie soll ich den "date" Objekte übergeben. Und wie soll ich entscheiden lassen was nun verwendet werden soll?
Ich gebe mal einen Hinweis als Code:
Und so wie die Funktion geschrieben ist, kann man wahlweise auch ein Tupel oder eine Liste mit Jahr, Datum, Tag übergeben. Durch Anwendung der *-Syntax (Tuple Unpacking) wird die Funktionssignatur recht flexibel an dieser Stelle.
Re: TypeError: unsupported operand type(s)
Verfasst: Mittwoch 16. Oktober 2024, 20:12
von Master_Shredder
Ich gebe mal einen Hinweis als Code:
WOW, genial! Danke für den Tipp.
Ich habe auch den Bezeichner angepasst @__blackjack__ hoffe dieser trifft jetzt besser zu.
Achso meinen IDE(PyCharm) gibt noch an ich soll die Methode in eine static Methode umwandeln???
Code: Alles auswählen
@staticmethod
def vergangene_zeit_ermitteln(
anfangsdatum: datetime, enddatum: datetime, einheit: Einheit
) -> float:
zeitspanne = enddatum - anfangsdatum
match einheit:
case "Tage":
return zeitspanne.total_seconds() / 86_400
case "Monate":
return zeitspanne.total_seconds() // 2_419_200 + 1
case _:
assert_never(einheit)
Code: Alles auswählen
@property
def grundpreis_tagesgenau_netto(self) -> float:
"""
Ermittlung des Grundpreises bis zum heutigen Tag netto
Returns
-------
float
"""
betrag_tag = self.nettobetrag_berechnen(self.tarif.grundpreis) * 12 / 365
tage = self.vergangene_zeit_ermitteln(
datetime(2024, 6, 13), datetime.now(), "Tage"
)
betrag = round(betrag_tag * tage, 3)
return betrag
Code: Alles auswählen
@property
def bisheriger_gezahlter_abschlag(self) -> float:
monate = self.vergangene_zeit_ermitteln(
datetime(2024, 6, 1), datetime.now(), "Monate"
)
betrag = monate * self.tarif.monatlicher_abschlag
return betrag
Re: TypeError: unsupported operand type(s)
Verfasst: Mittwoch 16. Oktober 2024, 20:20
von __blackjack__
@Master_Shredder: Eigentlich eher in eine Funktion, denn das hat ja mit der Klasse eigentlich nichts zu tun, sondern ist eine allgemein verwendbare Funktion.
Re: TypeError: unsupported operand type(s)
Verfasst: Freitag 18. Oktober 2024, 15:18
von Master_Shredder
Eigentlich eher in eine Funktion, denn das hat ja mit der Klasse eigentlich nichts zu tun, sondern ist eine allgemein verwendbare Funktion.
@__blackjack__ Ja, genau nur wenn ich die Methode dann als Funktion außerhalb der Klasse platziere, ist dies doch schlechter Programmierstil oder sogar nicht gut in Bezug auf die Sicherheit oder?
Da ich noch weitere Methoden habe, die allgemein verwendbar sind, dachte ich mir, lagere ich diese in ein extra Modul(im gleichen Package) aus.
Doch aus irgendeinem Grund heißt es im jetzigen Modul, wenn ich auf die äußeren Methoden zugreifen will "Parameter 'PARAMETER' unfilled"
Code: Alles auswählen
"""
Modul Abrechnung. Hier befinden sich die Klasse Abrechnung und die Methoden zur Berechnung des Verbrauches
und der Kosten
"""
from datetime import datetime
from berechnungen.berechnung import Berechnung
from datenbank.datenbankverbindung import Tarif, setup_session
class Abrechnung:
"""
Klasse Abrechnung
"""
def __init__(self, eingegebener_zaehlerstand: int, tarif):
self.eingegebener_zaehlerstand = eingegebener_zaehlerstand
self.tarif = tarif
@classmethod
def eingabe_zaehlerstand(cls, eingegebener_zaehlerstand: int):
session = setup_session()
tarif = session.get(Tarif, 2)
return cls(eingegebener_zaehlerstand, tarif)
@property
def verbrauch(self) -> int:
"""
Ermittlung des Verbrauches anhand des Zaehlerstandes vom Ende des letzten Rechnungszeitraumes
und des eingegeben Zaehlerstandes
Returns
-------
Int ermittelter Verbrauch
"""
betrag = (
self.eingegebener_zaehlerstand - self.tarif.zaehlerstand_letzte_abrechnung
)
return betrag
@property
def arbeitspreis_netto(self) -> float:
return Berechnung.nettobetrag_berechnen(self.tarif.arbeitspreis)
@property
def grundpreis_tagesgenau_netto(self) -> float:
"""
Ermittlung des Grundpreises bis zum heutigen Tag netto
Returns
-------
float
"""
betrag_tag = Berechnung.nettobetrag_berechnen(self.tarif.grundpreis) * 12 / 365
tage = Berechnung.vergangene_zeit_ermitteln(
datetime(2024, 6, 13), datetime.now(), "Tage"
)
betrag = round(betrag_tag * tage, 3)
return betrag
@property
def gesamtbetrag_netto(self) -> float:
betrag = self.arbeitspreis_netto + self.grundpreis_tagesgenau_netto
return betrag
@property
def gesamtbetrag_brutto(self) -> float:
betrag = Berechnung.bruttobetrag_berechnen(self.gesamtbetrag_netto)
return betrag
@property
def bisheriger_gezahlter_abschlag(self) -> float:
monate = Berechnung.vergangene_zeit_ermitteln(
datetime(2024, 6, 1), datetime.now(), "Monate"
)
betrag = monate * self.tarif.monatlicher_abschlag
return betrag
@property
def abschlag_jahresende(self) -> float:
"""
Hier wird die Summe des Abschlages bis zum Ende des Rechnungszeitraumes bei gleichbleibendem Betrag ermittelt
Returns
-------
float Summe des voraussichtlich eingezahlten abschlages für den gesamten Rechnungszeitraum
"""
betrag = self.tarif.monatlicher_abschlag * 12
return betrag
@property
def akt_kosten_abz_gezahlter_abschlag(self) -> float:
betrag = self.bisheriger_gezahlter_abschlag - self.gesamtbetrag_brutto
return betrag
@property
def akt_kosten_abz_gezahlter_abschlag_jahresende(self) -> float:
betrag = self.abschlag_jahresende - self.gesamtbetrag_brutto
return betrag
Code: Alles auswählen
from datetime import datetime
from typing import Literal, assert_never
from datenbank.datenbankverbindung import Tarif, setup_session
class Berechnung:
def __init__(self):
session = setup_session()
self.tarif = session.get(Tarif, 2)
type Einheit = Literal["Tage", "Monate"]
def nettobetrag_berechnen(self, bruttobetrag: float) -> float:
"""
Berechnet den Nettobetrag an einem uebergebenen Bruttobetrag anhand in der Datenbank hinterlegten Prozentsatz
Parameters
----------
bruttobetrag
Returns
-------
"""
mehrwertsteuer_betrag = bruttobetrag * self.tarif.mehrwertsteuer / 100
betrag = bruttobetrag - mehrwertsteuer_betrag
return betrag
def bruttobetrag_berechnen(self, nettobetrag: float) -> float:
"""
Addiert zu einem Betrag den in der Datenbank hinterlegten Prozentsatz
Parameters
----------
nettobetrag
Returns
-------
Betrag plus Mehrwertsteuer
"""
mehrwertsteuer_betrag = nettobetrag * self.tarif.mehrwertsteuer / 100
betrag = nettobetrag + mehrwertsteuer_betrag
return betrag
@staticmethod
def vergangene_zeit_ermitteln(
anfangsdatum: datetime, enddatum: datetime, einheit: Einheit
) -> float:
zeitspanne = enddatum - anfangsdatum
match einheit:
case "Tage":
return zeitspanne.total_seconds() / 86_400
case "Monate":
return zeitspanne.total_seconds() // 2_419_200 + 1
case _:
assert_never(einheit)
Re: TypeError: unsupported operand type(s)
Verfasst: Freitag 18. Oktober 2024, 17:27
von __blackjack__
@Master_Shredder: Im Gegenteil, schlechter Programmierstil ist es Funktionen in Klassen zu stecken. Wenn das schlechter Stil wäre, hätte man Funktionen als Sprachmittel ja einfach weg lassen können. Es gibt sie aber, und es gibt ja auch viele Funktionen in der Python-Standardbibliothek.
Was ist denn der Code zu der Fehlermeldung und wie sieht die genau aus? Das sieht nicht nach etwas aus was von Python selbst kommt.
``from berechnungen.berechnung import Berechnung`` sieht bedenklich aus. Das ist ja nicht nur ein Modul mit wahrscheinlich nur einer Klasse, sondern auch noch ein unnütz aussehendes Package in dem das dann noch mal drin ist. Wahrscheinlich sollte die Klasse schon nicht in einem eigenen Modul sein.
Re: TypeError: unsupported operand type(s)
Verfasst: Freitag 18. Oktober 2024, 18:23
von Master_Shredder
Was ist denn der Code zu der Fehlermeldung und wie sieht die genau aus?
Ah sorry, hatte ich vergessen.
Code: Alles auswählen
Traceback (most recent call last):
File "/home/masterblack/PycharmProjects/Verbrauchsrechner/verbrauchsrechner.py", line 30, in berechne
self.ui.arbeitspreis_netto.setText(f"{abrechnung.arbeitspreis_netto:.2f} €")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/masterblack/PycharmProjects/Verbrauchsrechner/berechnungen/abrechnung.py", line 43, in arbeitspreis_netto
return Berechnung.nettobetrag_berechnen(self.tarif.arbeitspreis)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Berechnung.nettobetrag_berechnen() missing 1 required positional argument: 'bruttobetrag'
Process finished with exit code 0
Code: Alles auswählen
@property
def arbeitspreis_netto(self) -> float:
return Berechnung.nettobetrag_berechnen(self.tarif.arbeitspreis)
@property
def grundpreis_tagesgenau_netto(self) -> float:
"""
Ermittlung des Grundpreises bis zum heutigen Tag netto
Returns
-------
float
"""
betrag_tag = Berechnung.nettobetrag_berechnen(self.tarif.grundpreis) * 12 / 365
tage = Berechnung.vergangene_zeit_ermitteln(
datetime(2024, 6, 13), datetime.now(), "Tage"
)
betrag = round(betrag_tag * tage, 3)
return betrag
@property
def gesamtbetrag_brutto(self) -> float:
betrag = Berechnung.bruttobetrag_berechnen(self.gesamtbetrag_netto)
return betrag
``from berechnungen.berechnung import Berechnung`` sieht bedenklich aus.
Ja, das "from berechnungen." kommt mir auch sehr redundant vor da "abrechnung.py" sich ja im gleichen Package befindet.
Im Gegenteil, schlechter Programmierstil ist es Funktionen in Klassen zu stecken.
Sollte ich die Klasse "Berechnung" komplett sein lassen?
Re: TypeError: unsupported operand type(s)
Verfasst: Freitag 18. Oktober 2024, 19:34
von __blackjack__
@Master_Shredder: Du versuchst da eine Methode auf der *Klasse* aufzurufen, statt auf einem Objekt das diese Klasse als Typ hat.
`Berechnung` kapselt ja eigentlich nur das `Tarif`-Objekt. Sieht für mich nicht so wirklich sinnvoll aus. `Abrechnung` eigentlich auch nicht. Wobei die Abrechnung ja auch einen Tarif kennt. Ist das der selbe? Wenn der nicht von dem `Berechnung`-Objekt abgefragt wird, wäre das komisch. Wobei es auch komisch wäre den von dem `Berechnung`-Objekt abzufragen. Mir würde auch so gar nicht gefallen das Objekte in der `__init__()` selbst eine Datenbankverbindung aufbauen und da Sachen abfragen. Wie testet man das denn dann ohne die Datenbank? So eine Abrechnung sollte die Logik für die Abrechnung enthalten und nichts von einer Datenbank wissen müssen.
Re: TypeError: unsupported operand type(s)
Verfasst: Freitag 18. Oktober 2024, 19:39
von Qubit
Ich weiß zwar nicht genau, was du da an Zeitdifferenzen berechnen willst, aber Python hat da schon etwas on board, nennt sich "relativedelta"..
Code: Alles auswählen
import datetime
from dateutil.relativedelta import relativedelta
def zeitspanne_ermitteln(start,end):
return relativedelta(end, start)
def main():
von='2024-10-10 00:45:10'
bis='2026-09-03 18:30:30'
start_time = datetime.datetime.strptime(von, '%Y-%m-%d %H:%M:%S')
end_time = datetime.datetime.strptime(bis, '%Y-%m-%d %H:%M:%S')
diff = zeitspanne_ermitteln(start_time,end_time)
print(f"Start: {start_time}")
print(f"End: {end_time}")
print(f"Differenz: {diff.years} Jahre, {diff.months} Monate, {diff.days} Tage, {diff.hours} Stunden, {diff.minutes} Minuten, {diff.seconds} Sekunden")
if __name__ == "__main__":
main()
Start: 2024-10-10 00:45:10
End: 2026-09-03 18:30:30
Differenz: 1 Jahre, 10 Monate, 24 Tage, 17 Stunden, 45 Minuten, 20 Sekunden
Re: TypeError: unsupported operand type(s)
Verfasst: Samstag 19. Oktober 2024, 15:24
von Master_Shredder
Du versuchst da eine Methode auf der *Klasse* aufzurufen, statt auf einem Objekt das diese Klasse als Typ hat.
Ja das stimmt, da Stimme ich zu.
Wobei die Abrechnung ja auch einen Tarif kennt. Ist das der selbe?
Ja ist der selbe Tarif.
Ist es so besser? Ich habe ein Objekt aus "berechnung" erstellt über welsches ich jetzt aufrufe.
Und die Funktionen in "berechnung" erhalten die "mehrwertsteuer" des "Tarif"-Objektes als Parameter.
Code: Alles auswählen
from datetime import datetime
from typing import Literal, assert_never
type Einheit = Literal["Tage", "Monate"]
def nettobetrag_berechnen(bruttobetrag: float, mehrwertsteuer: float) -> float:
"""
Berechnet den Nettobetrag an einem uebergebenen Bruttobetrag anhand in der Datenbank hinterlegten Prozentsatz
Parameters
----------
bruttobetrag
mehrwertsteuer
Returns
-------
"""
mehrwertsteuer_betrag = bruttobetrag * mehrwertsteuer / 100
betrag = bruttobetrag - mehrwertsteuer_betrag
return betrag
def bruttobetrag_berechnen(nettobetrag: float, mehrwertsteuer: float) -> float:
"""
Addiert zu einem Betrag den in der Datenbank hinterlegten Prozentsatz
Parameters
----------
nettobetrag
mehrwertsteuer
Returns
-------
Betrag plus Mehrwertsteuer
"""
mehrwertsteuer_betrag = nettobetrag * mehrwertsteuer / 100
betrag = nettobetrag + mehrwertsteuer_betrag
return betrag
def vergangene_zeit_ermitteln(
anfangsdatum: datetime, enddatum: datetime, einheit: Einheit
) -> float:
zeitspanne = enddatum - anfangsdatum
match einheit:
case "Tage":
return zeitspanne.total_seconds() / 86_400
case "Monate":
return zeitspanne.total_seconds() // 2_419_200 + 1
case _:
assert_never(einheit)
Code: Alles auswählen
"""
Modul Abrechnung. Hier befinden sich die Klasse Abrechnung und die Methoden zur Berechnung des Verbrauches
und der Kosten
"""
from datetime import datetime
from berechnungen import berechnung
from datenbank.datenbankverbindung import Tarif, setup_session
class Abrechnung:
"""
Klasse Abrechnung
"""
def __init__(self, eingegebener_zaehlerstand: int, tarif):
self.eingegebener_zaehlerstand = eingegebener_zaehlerstand
self.tarif = tarif
berechne = berechnung
@classmethod
def eingabe_zaehlerstand(cls, eingegebener_zaehlerstand: int):
session = setup_session()
tarif = session.get(Tarif, 2)
return cls(eingegebener_zaehlerstand, tarif)
.............
@property
def arbeitspreis_netto(self) -> float:
return self.berechne.nettobetrag_berechnen(
self.tarif.arbeitspreis, self.tarif.mehrwertsteuer
)
@property
def grundpreis_tagesgenau_netto(self) -> float:
"""
Ermittlung des Grundpreises bis zum heutigen Tag netto
Returns
-------
float
"""
betrag_tag = (
self.berechne.nettobetrag_berechnen(
self.tarif.grundpreis, self.tarif.mehrwertsteuer
)
* 12
/ 365
)
tage = self.berechne.vergangene_zeit_ermitteln(
datetime(2024, 6, 13), datetime.now(), "Tage"
)
betrag = round(betrag_tag * tage, 3)
return betrag
@property
def gesamtbetrag_netto(self) -> float:
betrag = self.arbeitspreis_netto + self.grundpreis_tagesgenau_netto
return betrag
@property
def gesamtbetrag_brutto(self) -> float:
betrag = self.berechne.bruttobetrag_berechnen(
self.gesamtbetrag_netto, self.tarif.mehrwertsteuer
)
return betrag
@property
def bisheriger_gezahlter_abschlag(self) -> float:
monate = self.berechne.vergangene_zeit_ermitteln(
datetime(2024, 6, 1), datetime.now(), "Monate"
)
betrag = monate * self.tarif.monatlicher_abschlag
return betrag
...............
Re: TypeError: unsupported operand type(s)
Verfasst: Samstag 19. Oktober 2024, 15:56
von narpfel
@Master_Shredder: `berechnungen.berechnung` ist immer noch eine Verschachtelung zu viel. Und `berechnung` ist auch nicht wirklich ein guter Name, weil zu allgemein (
alles, was ein Programm macht, ist im Endeffekt eine Berechnung).
`datenbank.datenbankverbindung` ist auch zu verschachtelt IMHO.
Warum hast du in der Klasse `berechne = berechnung` geschrieben?
Und (den Hinweis hat __blackjack__ sicher schon gegeben): Man muss nicht jedes Zwischenergebnis an einen Namen binden. Statt
Code: Alles auswählen
@property
def gesamtbetrag_brutto(self) -> float:
betrag = self.berechne.bruttobetrag_berechnen(
self.gesamtbetrag_netto, self.tarif.mehrwertsteuer
)
return betrag
besser
Code: Alles auswählen
@property
def gesamtbetrag_brutto(self) -> float:
return self.berechne.bruttobetrag_berechnen(
self.gesamtbetrag_netto, self.tarif.mehrwertsteuer
)
Und bitte unbedingt `--strict` für mypy benutzen, deine Typannotationen sind immer noch kaputt.
Re: TypeError: unsupported operand type(s)
Verfasst: Samstag 19. Oktober 2024, 16:14
von Sirius3
@narpfel: bei Sprachen, die Ducktyping unterstützen sind Typannotation per Definition kaputt.
Re: TypeError: unsupported operand type(s)
Verfasst: Samstag 19. Oktober 2024, 16:16
von narpfel
@Sirius3: Stimmt, aber wenn man schon Typannotationen benutzt, dann sollte man sie wenigstens so benutzen, dass sie korrekt sind. Selbst wenn sie dann zu einschränkend sind o. Ä.