Taugt mein Code etwas ...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Valentin KS
User
Beiträge: 10
Registriert: Samstag 12. Dezember 2020, 14:28
Wohnort: Kassel

... oder sollte ich ganz von vorn beginnen.

Hallo zusammen, wie ich hier schon festgestellt habe ist das Buch mit dem ich arbeite nicht sehr gut, daher habe ich jetzt versucht selbst etwas zuschreiben.
Das Skript läuft und tut was es soll, die Frage ist nur, ist das okay und in welchem Teil könnte es besser sein.
Ist es besser viele Zeilen zu haben oder lange Zeilen? (Abschnitt: def layout).

Sinn des Skripts:
Vergleich von Elektro- und Verbrennerfahrzeugen, anhand von Verbrauch, Preis pro Liter oder kw, anfallende Fixkosten. Eine der Fixkosten beim Verbrenner soll ab- und einschaltbar sein (geht), das Tankvolumen soll nach Passworteingabe zuschaltbar sein (nur vorbereitet, nicht Bestandteil dieser Frage)
Warum gerade das Skript??
Mir ist nichts besseres eingefallen was ich hätte machen können.

Für Eure Kritik schon mal ein Danke.

Code: Alles auswählen

from tkinter import *
from tkinter import messagebox

fgc='white'     # Schriftfarbe
bgc='darkred'   # Hintergrundfarbe
tl='Arial'      # Text der Label
sg=10           # Schriftgröße
sge=11          # Schriftgröße Button
opt='DISABLED'  # Startstatus der Eingabefelder
tkv='activ'     # vorbereitung Freischaltung

class Rechner:
    def __init__(self):
        self.fenster=Tk()
        self.fenster.title("Liter oder kw/h")
        #self.fenster.config(bg='darkred')
        
        self.opt=StringVar()
        self.tankv=StringVar()
        self.opt.set('disabled')    # Vorauswahl im Menü

        self.__addMenueleiste()
        self.__addOptionmenue()

        self.rahmen=Frame(master=self.fenster, relief=RIDGE, bd=4, bg=bgc,
                          padx=5, pady=5)
        self.title=Label(master=self.rahmen, fg=fgc, bg=bgc, width=30,
                         text="Verbrenner oder Stromer 2.2\nBETA", font=(tl,sg))
    # Verbrauch
        self.verbrauch=Label(master=self.rahmen, fg=fgc, bg=bgc,
                             text="Verbrauch", font=(tl, sg))
        # kw
        self.varAC=Label(master=self.rahmen, fg=fgc, bg=bgc,
                         text="kw", font=(tl,sg))
        self.varACEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.varACEntry.insert(0,"16.8")
        # Liter
        self.varL=Label(master=self.rahmen, fg=fgc, bg=bgc,
                        text="Liter", font=(tl, sg))
        self.varLEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.varLEntry.insert(0,"5.5")
    # Preise
        self.pP=Label(master=self.rahmen, fg=fgc, bg=bgc,
                      text="Preis pro...", font=(tl, sg))
        self.pKwEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.pKwEntry.insert(0,"0.40")
        self.pLEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.pLEntry.insert(0,"1.4")
    # Tank/Speicher
        self.tV=Label(master=self.rahmen, fg=fgc, bg=bgc,
                       text="Tankvolumen", font=(tl, sg))
        self.kwhEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.kwhEntry.insert(0,"0")
        self.kwhEntry.config(state=DISABLED)    #1
        self.literEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.literEntry.insert(0,"0")
        self.literEntry.config(state=DISABLED)  #1
    # Fixkosten
        self.TK=Label(master=self.rahmen, fg=fgc, bg=bgc,
                      text="Tankkarte", font=(tl, sg))
        self.TKEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.TKEntry.insert(0,"0")
        self.TK2Entry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.TK2Entry.insert(0,"0")
        self.TK2Entry.config(state=DISABLED)    #1

        self.TG=Label(master=self.rahmen, fg=fgc, bg=bgc,
                          text="Tankgebühr", font=(tl, sg))
        self.TGEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.TGEntry.insert(0,"0")
        self.TG2Entry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.TG2Entry.insert(0,"0")

        self.mtl=Label(master=self.rahmen, fg=fgc, bg=bgc,
                       text="mtl. Gebühr", font=(tl, sg))
        self.mtlEntry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.mtlEntry.insert(0,"5.99")
        self.mtl2Entry=Entry(master=self.rahmen, width=8, justify=RIGHT)
        self.mtl2Entry.insert(0,"0")
    # Summe
        self.rechButton=Button(master=self.rahmen, fg='red', command=self.rech,
                           text="Summe", font=(tl, sg), width=5)
        self.kwsummeAusgabe=Label(master=self.rahmen, width=8,
                                 text="-", font=(tl, sge))
        self.lsummeAusgabe=Label(master=self.rahmen, width=8,
                                 text="-", font=(tl, sge))
    # Günstigerprüfung
        self.günstiger=Label(master=self.rahmen, fg=fgc, bg=bgc,
                             text="günstiger ab: ", font=(tl, sg))
        self.günstigerAusgabe=Label(master=self.rahmen, width=8,
                                    text="-", font=(tl, sge))
        self.km=Label(master=self.rahmen, fg=fgc, bg=bgc,
                      text="km/tankung", font=(tl, sg))
    # Auswertung Günstigerprüfung
        self.nkmLabel=Label(master=self.rahmen, fg=fgc, bg=bgc,
                            text="nötige Tankung", font=(tl, sg))
        self.nkwAusgabe=Label(master=self.rahmen, width=8,
                              text="-", font=(tl, sge))
        self.nlAusgabe=Label(master=self.rahmen, width=8,
                             text="-", font=(tl, sge))
        self.layout()
        self.fenster.mainloop()
        
    def rech(self):
        vkw=float(self.varACEntry.get())    # Verbrauch kw/h je 100 km
        pkw=float(self.pKwEntry.get())      # Preis je kw/h
        endeKw=round((vkw*pkw),2)           # rundet das Ergebnis
        tvkw=float(self.kwhEntry.get())     # Kapazität des Akku in kw/h
        TK=float(self.TKEntry.get())        # Fixkosten für Tankkarte
        TG=float(self.TGEntry.get())        # Fixkosten für Tankgebühr
        mtl=float(self.mtlEntry.get())      # Fixkosten für mtl. Grundgebühr
        fixE=float(TK+TG+mtl)               # Summe Fixkosten

        vl=float(self.varLEntry.get())      # Verbrauch Liter je 100 km
        pl=float(self.pLEntry.get())        # Preis je Liter
        endeL=round((pl*vl),2)
        tvl=float(self.literEntry.get())    # Volumen des Tanks in Liter
        TK2=float(self.TK2Entry.get())      # Fixkosten Tankkarte
        TG2=float(self.TGEntry.get())       # Fixkosten Tankgebühr
        mtl2=float(self.mtlEntry.get())     # Fixkosten mtl. Grundgebühr
        fixL=float(TK2)

        pkmV=pl*vl      # Preis für 100 km Verbrenner
        pkmE=pkw*vkw    # Preis für 100 km Stromer

        if fixE >=1:
            km=((fixE-fixL)/(pkmV-pkmE))*100         # Formel optimale Tankung
            km=round((km),2)


            if endeKw >1:
                ausgabeKw=endeKw
                ausgabeKw=(ausgabeKw+fixE)
                ausgabeKwr=round((ausgabeKw),2)
                ausgabeKwr=str(ausgabeKwr)
                self.kwsummeAusgabe.config(text=ausgabeKwr+" €")

            if endeL >1:
                ausgabeL=endeL
                ausgabeL=(ausgabeL+fixL)
                ausgabeLr=round((ausgabeL),2)
                ausgabeLr=str(ausgabeLr)
                self.lsummeAusgabe.config(text=ausgabeLr+" €")
                self.günstigerAusgabe.config(text=format(km,",.2f"))
            if km <0:
                self.günstigerAusgabe.config(text="Nie")

        if fixE ==0:
            km=(1/(pkmV-pkmE))#*     # Formel optimale Tankung
            km=round((km),2)

            if endeKw >1:
                ausgabeKw=endeKw
                ausgabeKw=(ausgabeKw+fixE)
                ausgabeKwr=round((ausgabeKw),2)
                ausgabeKwr=str(ausgabeKwr)
                self.kwsummeAusgabe.config(text=ausgabeKwr+" €")

            if endeL >1:
                ausgabeL=endeL
                ausgabeL=(ausgabeL+fixL)
                ausgabeLr=round((ausgabeL),2)
                ausgabeLr=str(ausgabeLr)
                self.lsummeAusgabe.config(text=ausgabeLr+" €")
                self.günstigerAusgabe.config(text=format(km,",.2f"))
            if km <0.9:
                self.günstigerAusgabe.config(text="weniger 1")

        nkw=round((vkw*km/100),2)   # für optimale Strecke nötige kw
        nl=round((vl*km/100),2)     # für optilmae Stecke nötige Liter

        self.nkwAusgabe.config(text=nkw)
        self.nlAusgabe.config(text=nl)

    # Hervorhebung ob Akku/Tank ausreichen für optimale Strecke
        if tvkw > 0:
            if nkw > tvkw:
                self.kwhEntry.config(fg='red'), self.nkwAusgabe.config(fg='red')
            if nkw < tvkw:
                self.kwhEntry.config(fg='black'), self.nkwAusgabe.config(fg='black')
        if tvl > 0:
            if nl > tvl:
                self.literEntry.config(fg='red'), self.nlAusgabe.config(fg='red')
            if nl < tvl:
                self.literEntry.config(fg='black'), self.nlAusgabe.config(fg='black')

    def layout(self):
        self.rahmen.grid()
        self.title.grid(column=0, row=0, columnspan=3)

        self.varAC.grid(column=1, row=1, sticky=E), self.varL.grid(column=2, row=1, sticky=E)
    # Verbrauch
        self.verbrauch.grid(column=0,  row=2, sticky=E), self.varACEntry.grid(column=1, row=2, sticky=E, padx=5), self.varLEntry.grid(column=2, row=2, sticky=E)
    # Preis/Liter
        self.pP.grid(column=0, row=3, sticky=E), self.pKwEntry.grid(column=1, row=3, sticky=E, pady=5, padx=5), self.pLEntry.grid(column=2, row=3, sticky=E)
    # Tankvolumen
        self.tV.grid(column=0, row=4, sticky=E), self.kwhEntry.grid(column=1, row=4, sticky=E, padx=5), self.literEntry.grid(column=2, row=4, sticky=E)
    # Tankkarte
        self.TK.grid(column=0, row=6, sticky=E), self.TKEntry.grid(column=1, row=6, sticky=E, pady=5, padx=5), self.TK2Entry.grid(column=2, row=6, sticky=E)
    # Tankgebühr
        self.TG.grid(column=0, row=7, sticky=E), self.TGEntry.grid(column=1, row=7, sticky=E, padx=5), #self.TG2Entry.grid(column=2, row=7, sticky=E)
    # Grundgebühr
        self.mtl.grid(column=0, row=8, sticky=E)
        self.mtlEntry.grid(column=1, row=8, sticky=E, pady=5, padx=5)
        #self.mtl2Entry.grid(column=2, row=8, sticky=E)
    # Summe
        self.rechButton.grid(column=0, row=10, sticky=E)
        self.kwsummeAusgabe.grid(column=1, row=10, sticky=E, padx=5)
        self.lsummeAusgabe.grid(column=2, row=10, sticky=E)
    # optimale Strecke
        self.günstiger.grid(column=0, row=11, sticky=E)
        self.günstigerAusgabe.grid(column=1, row=11, sticky=E, padx=5)
        self.km.grid(column=2, row=11)
    # nötige Tankung für optimale Strecke
        self.nkmLabel.grid(column=0, row=12, sticky=E)
        self.nkwAusgabe.grid(column=1, row=12, padx=5, pady=5)
        self.nlAusgabe.grid(column=2, row=12, sticky=E)

# Menüleiste
    def __addMenueleiste(self):
        self.menueleiste=Menu(self.fenster)
        self.fenster.configure(menu=self.menueleiste)

# Menü Optionen
    def __addOptionmenue(self):
        self.optionmenue=Menu(master=self.menueleiste)
        self.brennermenue=Menu(master=self.optionmenue)
        self.tankmenue=Menu(master=self.optionmenue)

        self.menueleiste.add_cascade(label="Option",
                                     menu=self.optionmenue)
    # Fixkosten
        self.optionmenue.add_cascade(label="Brenner Fix",
                                 menu=self.brennermenue)
        self.brennermenue.add_radiobutton(label="An",
                                         variable=self.opt,
                                         value='normal', state=ACTIVE,
                                         command=self.fixanaus)
        self.brennermenue.add_radiobutton(label="Aus",
                                         variable=self.opt,
                                         value='disabled',
                                         command=self.fixanaus)
    # Tankvolumen
        self.optionmenue.add_cascade(label="Tankvolumen",
                                     menu=self.tankmenue)
        self.tankmenue.add_radiobutton(label="Tankvolumen", state=tkv,
                                       variable=self.tankv,
                                       command=self.tank)
        
    # Ausführung
    def fixanaus(self):       # schaltet Feld frei
        opt=self.opt.get()
        self.TK2Entry.config(state=opt)
        if opt =='disabled':
            messagebox.showwarning("Hinweis", "Bitte führen Sie eine erneute Berechnung durch.")

    def tank(self):     # Aktiviert die Felder
        messagebox.showwarning("!!","Das hat geklappt")
        self.kwhEntry.config(state=NORMAL)
        self.literEntry.config(state=NORMAL)

r=Rechner()
Gruß
Valentin
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Vermutlich wird noch jemand etwas Ausführlicheres dazu schreiben, aber du könntest in der Zwischenzeit schon mal anfangen, den offiziellen Style Guide for Python Code zu lesen.
Benutzeravatar
__blackjack__
User
Beiträge: 14065
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Valentin KS: Sternchen-Importe sind Böse™. Damit holt man sich gerade bei `tkinter` ca. 200 Namen ins Modul. Und nicht nur welche die im `tkinter`-Modul definiert sind, sondern auch welche die `tkinter` seinerseits von woanders importiert.

Neben den Namenschreibweisen die sich nicht am von /me verlinkten Style Guide halten, sollte man auch keine kryptischen Abkürzungen verwenden. Die ganzen Kommentare die erklären was die Konstantennamen am Anfang bedeuten sollen, könnte man sich beispielsweise sparen wenn man die Namen sinnvoll wählen würde.

Die doppelten führenden Unterstriche bei den zwei Methoden, welche die benutzen, gehören da nicht hin. Entweder ein führender Unterstrich oder gar keiner. Falls Dein Lernmaterial behauptet zwei währen so etwas wie ``private`` in anderen Programmiersprachen, vergiss das gleich wieder.

In der `layout()`-Methode erstellst Du sinnlose Tupel mit denen nichts gemacht wird. Kommas sind nicht dazu da um Anweisungen/Ausdrücke zu trennen, die erstellen an der Stelle Tupel. Anweisungen trennt man anders. Ich verrate jetzt mal nicht wie, denn man schreibt sowieso eine Anweisung pro Zeile, und nicht mehrere.

Auch hier sieht man wieder schön warum kryptisch abgekürzte Namen doof sind. Statt vernünftige Namen zu verwenden, stehen da wieder lauter Kommentare die dem Leser verraten was der Name bedeuten soll.

Das Layouten vom erstellen der Anzeigeelemente zu trennen ist unübersichtlich. Und es macht es unnötig schwer wenn man da mal Teile der GUI in eine eigene Klasse herausziehen möchte.

Nachdem die `__init__()` durchgelaufen ist, sollte man ein benutzbares Objekt haben. In die `__init__()` gehört deshalb nicht der komplette Programmablauf, denn momentan kehrt die `__init__()` erst zum Aufrufer zurück wenn der Benutzer die GUI geschlossen hat. Dann kann man aber mit dem `Rechner`-Objekt nichts mehr anfangen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Valentin KS
User
Beiträge: 10
Registriert: Samstag 12. Dezember 2020, 14:28
Wohnort: Kassel

@/me
@ __blackjack__
Okay, danke, ich werde der Verlinkung und den anderen Hinweisen nachgehen.
Wenn das mit den zwei Unterstrichen nicht privat ist kann ich ziemlich weit zurück gehen.
Das mit den * Importen war mir zwar irgendwie klar aber besser hab ich's leider nicht gelernt. :(
Bei den Abkürzungen hab ich damit gerechnet. So sieht's in meinem Kopf halt aus :D
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Valentin KS hat geschrieben: Dienstag 31. August 2021, 19:23 Wenn das mit den zwei Unterstrichen nicht privat ist kann ich ziemlich weit zurück gehen.
Es ist ja nicht so, als ob alles was du seitdem gelernt hast falsch ist. Es ist nur so, dass zwei führende Unterstriche nicht "privat" bedeuten. Jemand der das so erklärt versucht das Konzept von "public - protected - private" auf Python zu übertragen und das ist falsch.

Ein führender Unterstrich sagt einem anderen Entwickler: Das ist intern, lass mal lieber die Finger davon weg. NIchts hindert den anderen Entwickler aber daran, das Attribut mit dem führenden Unterstrich trotzdem (auf eigene Gefahr) zu verwenden und das ist auch gut so. Zwei führende Unterstriche aktivieren bei der Vererbung von Klassen einen name-mangling Mechanismus der Namenskollisionen verhindern soll. Das Problem hat man eher selten und auch in diesem Fall ist das Attribut nicht privat, es ist nur nicht unter seinem ursprünglichen Namen auffindbar.


Aber die Namen der Variablen in deinem Code sind wirklich grausam. Ich fühl mich ja in die Zeiten zurückversetzt als ich Programme noch in Cobol, PL/1 oder klassischem RPG geschrieben habe.
Antworten