Hilfe für *kwarks

Django, Flask, Bottle, WSGI, CGI…
Antworten
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

Ich versuche ja nebenbei immer meinen Code zu verbessern und vermute, dass ich mit "kwargs" Vereinfachungen erreiche, habe das aber (wiedrmal) nicht so ganz verstanden. Meine Rechentraineruser wählen durch Klick auf eine Kategorie ein von (zurzeit noch) 15 Kategorien aus.

Code: Alles auswählen

#Dict zum Zuordnen der kategorie.zeile zu den einzelnen Aufgaben:
AUFGABEN = {
    1: addieren, 2: subtrahieren, 3: verdoppeln, 4: halbieren, 5: einmaleins, 6: kopfrechnen, 7: sachaufgaben, 8: zahlen, 9: malget10, 10: runden, 
    11: regeln, 12: geometrie, 13: einheiten, 14: figuren, 15: kommazahlen, 16: zuordnungen}
Sie übergeben den Namen der Kategorie (slug) an die Funktion "main".

Code: Alles auswählen

path('<slug:slug>/', views.main, name='main')
Die Aufgaben der einzelnen Kategorien werden jeweils in einer Funktion erzeugt.
Innerhalb von "main" ruft die Codezeile:

Code: Alles auswählen

typ, typ2, titel, text, pro_text, frage, variable, einheit, anmerkung, lsg, hilfe_id, ergebnis, parameter = aufgaben(kategorie.zeile, jg = user.jg, stufe = user.stufe, aufgnr = zaehler.aufgnr, typ_anf = typ_anf, typ_end = zaehler.typ_end, optionen = "") 
die Funktion "aufgaben" auf:

Code: Alles auswählen

def aufgaben(kategorie_id, jg = 5, stufe = 3, aufgnr = 0, typ_anf = 0, typ_end = 0, typ = 0, typ2 = 0, optionen = "", eingabe = "", lsg = ""):
    return AUFGABEN[kategorie_id](jg, stufe, aufgnr, typ_anf, typ_end, typ, typ2, optionen, eingabe, lsg)
(Die Grundstruktur ist von @whitie)
und von da aus wird dann z.B. die Funktion "addieren" aufgerufen:

Code: Alles auswählen

def addieren(jg = 5, stufe = 3, aufgnr = 0, typ_anf = 0, typ_end = 0, typ = 0, typ2 = 0, optionen = "", eingabe = "", lsg = ""):
... ich gehe davon aus, dass man das mit "kwarks" stark vereinfachen kann - habe aber Angst was kaputt zu machen.
(Hoffentlich habe ich das gut genug erklärt :? )
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Falls du mit den ganzen Variablen noch andere Dinge machst, hätte ich wahrscheinlich eine Klasse dafür genommen. Sonst ist evtl. ein Wörterbuch das richtige. Sähe dann etwa so aus:

Code: Alles auswählen

aufgabenparameter = aufgaben(kategorie.zeile, jg = user.jg, stufe = user.stufe, aufgnr = zaehler.aufgnr, typ_anf = typ_anf, typ_end = zaehler.typ_end, optionen = "")
# für die Klasse:
addieren(aufgabenparameter)
# Dict ginge dann auch:
addieren(**aufgabenparameter)
Ohne Kontext kann man schwer sagen, ob da was besser/einfacher wäre.

Viele Grüße
Whitie

P. S. Da ist meine Grundstruktur aber ordentlich gewachsen ;-)
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man zu viele Parameter hat, dann packt man die in einer Klasse sinnvoll zusammen und übergibt nur eine Instanz der Klasse.

Defaultargumente sollten wirkliche Defaults sein. Die Jahrgangsstufe ist etwas, was man immer angeben sollte, warum ist dann der Default von jg gerade 5?
Und wiedereinmal der Hinweis darauf, keine kryptischen Abkürzungen zu benutzen, jahrgang ist lesbar jg nicht. aufgabe_nummer läßt sich viel schneller Erfassen als ein aufgnr zu entschlüsseln. Und das bei jedem mal Lesen!
Keine Ahnung was der Unterschied zwischen typ, typ2, typ_anf und typ_end ist. Das sollte aus dem Variablennamen klar werden.
Benutzeravatar
noisefloor
User
Beiträge: 3857
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

vereinfachen im eigentlichen Sinne - nein. Wenn die Parameter alle sinnvoll und nötig sind, dann hast du halt so viele Parameter. Klar kannst du die Parameter vorher zu einem Dict zusammenziehen und dann als **kwargs übergeben - ändert aber in der Funktion, die die ganzen Parameter braucht, nichts. Also die wird weder einfacher noch kürzer.

Eine Vereinfachung wäre, wenn du X Parameter mit (sinnvollen) Defaultwerten belegen könntest, so dass du der Funktion nicht jedes mal alle Parameter mitgeben müsstet.

Wenn ein Wert nicht belegt ist übergibt man besser `None` statt `""`, also z.B. `optionen=None` statt `optionen=""`.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

Whitie hat geschrieben: Mittwoch 5. April 2023, 13:17 P. S. Da ist meine Grundstruktur aber ordentlich gewachsen ;-)
"Deine" Funktion "main" hat jetzt schon über 3350 Zeilen.
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

noisefloor hat geschrieben: Mittwoch 5. April 2023, 13:43 vereinfachen im eigentlichen Sinne - nein.
Auch das da nicht? Ich finde, das sieht komisch aus:

Code: Alles auswählen

def aufgaben(kategorie_id, jg = 5, stufe = 3, aufgnr = 0, typ_anf = 0, typ_end = 0, typ = 0, typ2 = 0, optionen = None, eingabe = None, lsg = None):
    return AUFGABEN[kategorie_id](jg, stufe, aufgnr, typ_anf, typ_end, typ, typ2, optionen, eingabe, lsg)
Benutzeravatar
noisefloor
User
Beiträge: 3857
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wie gesagt, die änderst den Aufruf ja nicht und änderst die Parameter für die Funktion nicht. Du verschiebst ja "nur" wo wie was im Quelltext definiert wird.
Wenn das für dich dann schöner / übersichtlicher ist - ok. Hier gibt es ja kein echtes "richtig" oder "falsch".

Ich hatte mal einen ähnlichen Fall, da habe ich die Parameter in eine dataclass gepackt und die dann rumgereicht. Allerdings waren die Parameter auch komplexer vom Datentyp / der Datenstruktur her. Oder halt alles direkt in eine Klasse, wurde ja bereits erwähnt.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

OK, ich wollte halt nur sicherstellen, dass niemand lacht ,wenn er meinen Code zu Gesicht bekommt. Obwohl ... da gibt es sicher noch mehr Gründe.
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

ich misch mich auch mal ein, will auch nicht den Klugscheisser raus hängen lassen (hoffentlich passt folgendes auch), aber es könnte bei deiner Überschrift Verwechslungsgefahr bestehen. EIn Stern wird üblicherweise für 'args' benutzt, das steht dabei für 'arguments' und ist mit einer Liste vergleichbar. 'kwargs' wird mit zwei Sternen benutzt und steht für 'keyword-arguments' und ähnelt einem Wörterbuch. Wobei du die Namen auch anderst wählen kannst, 'kwarks' funktioniert auch oder andere, eventuell aussagekräftige Namen mit den entsprechenden Strenchen.

Wenn jemand über Code von jemanden lacht, der sich das Programmieren mühevoll selbst bzw. mit Hilfe eines Forums beibringt, der hat sicherlich andere Probleme.
Aber mein Anspruch ist auch immer, dass die Profis hier so wenig wie möglich zu kritisieren haben. 🧐
Auch das da nicht? Ich finde, das sieht komisch aus:
Ich finde auch dass das komisch aussieht. Da würde ich mir den Beitrag von @Sirius3 noch einmal anschauen.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
DeaD_EyE
User
Beiträge: 1021
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Pitwheazle hat geschrieben: Mittwoch 5. April 2023, 16:48 OK, ich wollte halt nur sicherstellen, dass niemand lacht ,wenn er meinen Code zu Gesicht bekommt. Obwohl ... da gibt es sicher noch mehr Gründe.
Nein, wir werden dann nur an unseren eigenen Code erinnert, der manchmal auf magische Weise einen noch nach 10 Jahren verfolgt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Mittwoch 5. April 2023, 13:38 Wenn man zu viele Parameter hat, dann packt man die in einer Klasse sinnvoll zusammen und übergibt nur eine Instanz der Klasse.
Da kommt wieder die Frage eines beschränkten Users: Wie müsste das aussehen?
Ich habe ja diese Zeile

Code: Alles auswählen

def xxxxxxx(jg = 5, stufe = 3, aufgnr = 0, typ_anf = 0, typ_end = 0, typ = 0, typ2 = 0, optionen = "", eingabe = "", lsg = ""):
zurzeit 16 mal, das werden ja aber mal 35 Funktionen. Da ist es lästig, wenn ich Veränderungen 35 mal vornehmen muss.
Sirius3 hat geschrieben: Mittwoch 5. April 2023, 13:38 Defaultargumente sollten wirkliche Defaults sein. Die Jahrgangsstufe ist etwas, was man immer angeben sollte, warum ist dann der Default von jg gerade 5?.
Nun ja, wenn ich kein default angebe, können Nutzer auch die Null übernehmen und das macht nicht so viel Sinn. Ich hatte das mit min und max mal probiert, da das nicht auf Anhieb hingehauen hat, habe ich mir so beholfen. Wenn du das aber als nicht so sinnvoll erachtest, probiere ich mich noch mal dran.
Sirius3 hat geschrieben: Mittwoch 5. April 2023, 13:38 Und wiedereinmal der Hinweis darauf, keine kryptischen Abkürzungen zu benutzen, jahrgang ist lesbar jg nicht. aufgabe_nummer läßt sich viel schneller Erfassen als ein aufgnr zu entschlüsseln. Und das bei jedem mal Lesen!
Keine Ahnung was der Unterschied zwischen typ, typ2, typ_anf und typ_end ist. Das sollte aus dem Variablennamen klar werden.
Es ist nicht so, dass ich deine Anmerkung nicht berücksichtigt habe, ich habe aufgrund deines Hinweises schon sehr viele Variablennnamen geändert.
Jede meiner Aufgabenkategorien haben im Normalfall nochmals einige Unterkategorien, die habe ich halt typ genannt und wenn diese weitere Unterkategorien haben, heißen diese typ2. Im Protokoll wird auch immer angezeigt, welchem Typ die Aufgabe zugeordnet ist.
Ich habe auch versucht, in den Kommentaren das ordentlich zu erklären.
Außerdem ist das meinem existierenden Rechentrainer geschuldet, der ist auch so aufgebaut.
Und typ_anf und typ_ end wird beim Start der jeweiligen zehn Aufgaben (die am Stück gerechnet werden müssen) nach Jahrgang, Stufe, (Leistungs)kurszugehörigkeit sowie einer explizieten Auswahlsmöglichkeit seitens des Users festgelegt. Innerhalb typ_anf und typ_end werden die Aufgaben erzeugt. Was besseres ist mir nicht eingefallen und ich denke, das ergibt sich auch wenn man meinen Code sieht.
Antworten