Transcript: Fragen über Fragen
Full episode transcript. Timestamps refer to the audio playback.
Ja, hallo liebe Hörerinnen und Hörer. Willkommen bei einem Python-Podcast in der 15. Episode.
Hier ist der Dominik, bei mir ist der Jochen. Wir sind wieder im Wintergarten.
Hallihallo.
Diesmal scheint sogar noch die Sonne zu sein. Wahnsinn.
Ja, es ist auch selten, dass wir aufnehmen, wenn es noch hell ist, aber heute hat es geklappt.
Ja, wir haben tatsächlich Dezember irgendwie.
Ja, der 12. Dezember, genau. Vielleicht gar nicht so schlecht, wenn wir das mal dazusagen, wann das ist.
Ja, wir haben uns ein bisschen Zeit gelassen in letzter Zeit mit den Folgen, es war so viel zu tun,
aber wir versprechen, wir werden es nicht aufgeben und euch weiter damit bespaßen können.
Ich wollte ja nicht belästigen sagen.
Ja, genau. Das ist aber die Frage, was man da empfindet, wenn man das hört.
Unsere Folge heute soll wirklich mal so eine Anfängerfolge sein.
Ja, wir werden mit euch heute reden über ein, zwei Fragen, die wir stellen möchten.
Was für Anfänger für Fragen haben oder was mir eingefallen ist oder was einige Hörer uns geschrieben haben.
Worum es eigentlich bei Python geht. Ein paar ganz grundlegende Sachen.
Vielleicht wird es ja spannend.
Also, ja, keine Lava-Folge, kennt ihr schon.
Wen ihr schon gehört habt.
Ja, ja.
Genau, das mit den Themen können wir auch
irgendwann mal klassen.
Die nächste Lava-Folge.
Ja, was machen wir hier eigentlich heute?
Und was ist so passiert in der Szene?
Und gibt es irgendwas Neues?
Nee, nicht, dass ich, ich glaube,
seit dem letzten Mal hat sich da gar nicht so viel getan.
Django 3 ist raus.
Oh ja, doch, ja, richtig, du hast recht.
Ja, tatsächlich, Django 3 ist raus
und das war, das ist natürlich eine tolle Geschichte.
Ich habe das direkt mal versucht
zu installieren und da so ein paar Sachen
irgendwie mitzumachen, aber
habe dann feststellen müssen,
dass ein Haufen der Abhängigkeiten, die man so defaultmäßig
irgendwie in Django-Projekten drin hat,
dann nicht mehr so richtig
funktioniert haben, beziehungsweise dazu führen, dass man
halt ein Traceback kriegt, wenn man was für den Entwicklungsserver
zu starten und
ja, unter anderem sowas wie
Django-Model-Utils, was
irgendwie fast alle Leute, also ich verwende
das eigentlich immer. Wahrscheinlich auch eine Menge andere Leute
wegen
Timestamp-Model oder so, was man ja
oft verwendet.
Ich weiß nicht mehr genau,
was es noch alles war.
Ich habe dann für die Sachen, die
nicht funktioniert haben, da habe ich dann
einfach die geforkt auf GitHub
und
habe das dann versucht zu fixen und dann halt
entsprechend immer Pull-Requests aufgemacht.
Also das heißt, ihr könntet bei Jochen
in den Repos versuchen, die auch bei
Dango 3 funktionieren?
Nein, nee, das sollte man vielleicht
nicht machen, also
Daran wird sich das irgendwie
mitten oder so, nee, nee, nee
Aber es hat mich gewundert, wie viel da noch
nicht funktioniert hat, also es war bei so einem
normalen, ich weiß nicht, bei welchem
ich das probiert habe, entweder bei einer Webseite oder
auch bei der Python-Podcast
Projekt-Dings
habe ich mal versucht, das auf Django 3
umzustellen und das ist
mit fünf
Einhängigkeiten oder so sind kaputt gegangen
und ich glaube, ich habe auch so fünf Pull-Requests
irgendwie gemacht. Also bei Danko gibt es irgendwie
immer drei oder vier Versionen, oder nee, drei.
Also 0, 1 und 2 und dann ist
nämlich das Major Release. War das nochmal was?
Also ich glaube 0 ist immer so die neue
Feature-Sachen? Nee, ist immer
gerade, ungerade. Gerade
sind immer die Long-Term. Ich glaube
2 ist Long-Term. Punkt 2.
Also 2.2, 1.2, 3.2
sind die Long-Term.
Und 1...
Ich bin mir sicher. Okay, gut, sehr gut.
Und 1 ist irgendwas anderes, das weiß ich
nicht. Aber ja, deswegen habe ich nur gefragt.
was man dann macht? Also für Security-Patches dann wahrscheinlich
mal die Zweier-Version nehmen, dass man irgendwie stabil sein möchte?
Nee, also das, was tatsächlich
empfohlen wird eigentlich,
also das ist auch so eine Legacy-Geschichte,
das mit den Long-Term-Support-Geschichten.
Und
naja, jedenfalls sagt das
derjenige, der aktuell irgendwie
da ja auch hauptruflich
für das Django-Projekt arbeitet,
Carlton Gibson,
dass er empfehlen würde
und das machen eigentlich alle
Leute, die
da wirklich viel Ahnung
von haben, dass man halt, also
früher war das wohl mal anders, aber mittlerweile sind
die neuen Versionen von Django so stabil
und so gut getestet, dass man eigentlich
immer möglichst nah dran an
der Entwicklung bleiben sollte.
Weil es auch gar nicht mehr so schlimm ist, bis dahin
abzudaten. Es geht gar
nicht mehr so viel kaputt. Sollte eigentlich nicht.
Ja, wir haben gerade gesehen, genau.
Also eigentlich, weil das halt
macht halt viele andere Sachen deutlich einfacher, wenn man
das so rummacht. Und wenn man halt
auf der Long-Term-Support-Version sitzt, dann
ja, hat man halt irgendwann
ein großes Problem und das
will man vielleicht dann doch nicht. Also
die Art, wie man das heute macht, aber auf der anderen Seite machen das
viele Leute schon seit langer Zeit so.
Insofern kann man, die kann man auch nicht einfach alle so vor den Kopf
stoßen, aber
so wie man das heute eigentlich machen
sollte, ist eigentlich immer die aktuellste
Django-Version verwenden.
Okay. Und ich
versuche das auch immer und normalerweise funktioniert, also bis jetzt
auch die 2er-Serie hat das eigentlich sehr gut funktioniert,
bis jetzt Umstieg auf 3, da hat es halt nicht mehr funktioniert.
Und das war auch in allen Fällen das gleiche Problem.
Und zwar sind halt so ein paar private APIs
für die Unterstützung von so alten Python-2-Geschichten
sind jetzt aus Django 3 rausgeflogen.
Also eigentlich gibt es ja keinen Python-2-Support mehr,
auch seit Django 2 schon nicht mehr.
Oh, das läuft ja aus.
Wir können ja runterzählen, es sind nur noch Tage.
Ja, es sind nur noch Tage, bis es irgendwie vorbei ist.
18, 19.
Ja.
Ja.
Aber es waren noch so ein paar
Geschichten dabei,
so zum Beispiel, man konnte irgendwas, es gab so einen
Dekorator-Pi2-Unicode-String
oder sowas, den man über Funktionen
setzen konnte und dann kam das halt mit
auch den alten
Geschichten klar und
Six gab es halt auch
in Django drin.
Was auch immer Six ist. Ja, auch so eine Geschichte, die einem
helfen soll, damit
umzugehen, wenn es halt
ja, Python 2
und Python 3 Geschichten sind.
Ich unterbreche dich gerade ungenau. Wir haben eigentlich versprochen,
dass es eine Anfängerfolge sein sollte.
Und wir fangen schon mit der Ahnung ganz tief in die Materie reinzugehen.
Nee, das ist eigentlich auch nicht so.
Es sind ein paar Hilfsfunktionen,
die einem dabei helfen, das für Python 2
und Python 3 gleichzeitig zu machen.
Die sind jetzt tatsächlich
entfernt worden. Die waren vorher bloß deprecated,
aber jetzt sind die halt wirklich weg.
Und das heißt, wenn jemand die noch
verwendet, ein Paket, die noch verwendet,
dann gibt es halt ein Traceback an der Stelle.
Also alles, was jetzt in Python 3 deprecated
angezeigt wird, ist bei Python 4 dann weg.
Bei Python, sag ich schon. Bei Django 3, 4.
Ja, also diese
Geschichten waren jetzt halt dann
weg. Und das hat
dann auch diverse Pakete gebrochen
und insofern, ja, also
Umstieg auf Django 3 nicht so super easy.
Wie lange ist es, bis Django 2 rauskam?
Wie lange das her ist?
Ich weiß es nicht mehr genau.
Ich würde mal so tippen. Ages.
Ja, fast zwei Jahre oder so.
irgendwas um die zwei Jahre ein bisschen?
Das geht ja. Ja, also die
Release-Zyklen bei Django sind ja auch viel kürzer geworden.
das war früher alles viel länger und
ja, Django 2 gab es
jetzt gar nicht so lang. Ja, wenn du noch
welche News einst, weil sonst machen wir tatsächlich weiter mit
Content heute. Ja, ne, Content
klingt gut. Also ich stelle
jetzt immer ein paar blöde Fragen
und ich
versuche dich dazu zu bringen, dass du die Fragen möglichst
kurz beantwortest.
Oder so eine Minute pro Fage oder so.
Vielleicht schaffen wir das.
Wow, okay.
Ja, alles klar.
Ich weiß, es wird nicht immer ganz einfach bei einigen Themen.
Das ist natürlich auch was anderes.
Aber mal gucken.
Ja, schauen wir einfach mal.
Also erste Frage.
Ist Python eine Schlange?
Ah, wo kommt der Name her?
Also, nee, tatsächlich ist das eine Referenz auf Monty Python.
Spam, Spam, Spam, Spam, Spam, Spam.
Genau, genau.
auch interessant,
der
Monty Pythons
Flying Circus, also
der Flying Circus ist wiederum
eine Anspielung auf, glaube ich,
Ersten Weltkrieg, Roter Brunnen,
irgendwie, Geschichte.
Die nannte man
halt, das war halt so die
informelle Bezeichnung,
weil die halt immer mit Zelten auf irgendwelchen
Äckern und Wiesen unterwegs waren,
weil es sowas wie Flugplätze ja damals noch gar
nicht gab, wurden die dann halt auch mal
der fliegende Zirkus genannt und
ja,
ja, aber wo
Monty Python eigentlich herkommt,
weiß ich jetzt auch nicht. Also Guido hat sich das dann ja irgendwie
so ausgedacht. Genau, also
die Referenz
des Namens der Programmiersprache
bezieht sich schon auf Monty Python.
Also ich finde aber eine Schlange eigentlich viel cooler
und ich würde einfach sagen, ich nehme auch immer so eine Schlange als Symbol
und es ist ja sogar im Logo mittlerweile drin.
Nee, klar.
Wenn ich mir ganz viele
Python-Muster auf mein Körper
tätowieren lasse, dann ist das natürlich ein Zeichen von meiner
Liebe zur Sprache.
Tja. Ja, man kann sich ja schlecht nur
irgendwelche Gags auf den Körper tätowieren lassen, das geht natürlich nicht.
Ich habe übrigens noch keine Tattoos.
Leider, meine Frau sagt, ich darf nicht.
So. So, so. Ja.
Tja, da musst du dich wohl entscheiden.
Ja.
Nächste Frage wäre,
welche Einsatzzwecke von Python fallen dir ein?
Na ja, schon eine ganze Menge,
aber ich würde sagen, die allerwichtigsten zur Zeit
sind, ja,
Data Science ist jetzt, glaube ich, das
am stärksten gehypte Thema momentan.
Immer noch sogar. Ja, doch, ich denke schon.
Einfach deswegen, weil das halt
irgendwie alle machen wollen, weil da auch viele
Fortschritte passieren und Python ist halt
die
Programmiersprache, mit der man das vielleicht am besten machen kann,
abgesehen von R. Aber R ist halt
ein bisschen, hat ein bisschen einen engeren Einsatzzweck
und du kannst halt nicht gut
Webgeschichten zum Beispiel nachschreiben oder so.
Oder ganze komplette Systeme in R bauen, das geht eigentlich
nicht gut. Aber mit Python geht das, daher ist
Python irgendwie da
schon so, gerade für produktive
Geschichten, das Mittel der Wahl.
Also wenn man jetzt nicht nur Sachen analysieren möchte
oder explorative Analyse von irgendwas
machen möchte, sondern man möchte es tatsächlich einsetzen, dann
kommt man eigentlich um Python nicht wirklich
drumherum. Es gibt ja auch noch so ein paar Leute, die dann
irgendwie, oder sagen wir so, das ist auch ein großer
Bereich, aber die dann Java oder so verwenden.
Es gibt ja auch irgendwie mit Scala,
also nicht Java, sondern die Java4M
und meistens verwenden die Leute dann irgendwie Scala
obendrauf
und Spark und da gibt es auch so DataFrames.
Aber
ich würde sagen, das ist ein deutliches Stück kleiner
als der
PyData-Stack.
Ja, also das ist auf jeden Fall
das größte
Thema, glaube ich, momentan, aber Web-Entwicklung
ist nach wie vor auch sehr groß.
Dann eine Geschichte, die
jetzt kommt irgendwie,
da wollen wir auch unbedingt
nochmal was zu machen,
ist alles, was irgendwie so mit Home-Automation
Zeugs zu tun hat. Home Assistant
ist ein
großes Thema. Ich habe da letztens
so um Weihnachten rum, dann kann ich auch noch mal
gucken, ob diese ganzen Geschichten noch
gehen oder Geschenke in bestimmte Richtungen
werfen, die irgendwas in der Art
tun, weil das ja doch eine ganz angenehme
Sache ist, wenn man halt Lampen und sowas
automatisch steuern kann. Das ist natürlich ganz spannend,
weil man hat halt irgendwie ganz viel
kleines Zubehör, das irgendwie, wenn ich das richtig mal verstehe,
meistens so in C am besten programmiert ist.
Man hat irgendwie so eine High-Level-API, so wie MicroPython
oder sowas, die man da drauf schmeißt und kann dann einfach in Python
auch die ganzen Module nehmen.
Ja, also die ganzen
Endgeräte,
das ist ja die Frage. Also man kann das, wenn das so
Arduino-mäßig ist, ist das auf C, was man
normalerweise schreibt, aber
es gibt halt auch mittlerweile Chips, auf denen
man Mikro-Python
installieren kann und dann kann man da einfach Python schreiben.
Die haben halt WLAN und ansonsten hast du
ein Problem, wie kommunizierst du eigentlich mit Sensoren
oder irgendwelchen Dingen, die dann was schalten oder so.
Wenn du da
irgendwie das über Funk, DVB-T oder so
machen, also ein bisschen ätzend.
Und WLAN ist natürlich schon nicht so schlecht und das geht eigentlich
mit alles mittlerweile. Aber halt eben, ich glaube,
der größte Punkt ist, dass Home Assistant
ist halt in Falken geschrieben und das ist halt das Ding,
was zum Verwalten von diesem ganzen Kram halt
üblicherweise so verwendet wird, wenn man
jetzt nicht irgendeine fertige Lösung
wie jetzt, na, wie heißt
das denn, von Apple
oder Google oder
Amazon oder so, die haben natürlich ihre
eigenen Geschichten.
Und was ich da interessant, ich habe da letztens noch mal
genau in dem Zusammenhang mir dieses State of the
Union von Home Assistant
den Talk angeguckt und
das war mir gar nicht so
klar, dass die mittlerweile unter den
Top Ten der
Projekte bei GitHub sind, die am meisten
Contributions kriegen. Okay, cool.
Ja, weil die Leute am meisten gerne daran basteln, ne?
Ja, ich war
überrascht, wie viel das ist, weil
das ist ja jetzt eben noch nicht so prominent
als, ich glaube, es waren sowieso sehr wenig
Open-Source-Projekte in den ersten 10.
Also da waren eher solche, das fand ich
auch so ein bisschen erschreckend. Wir haben doch keine
Zeit. Aber sowas wie
Visual Studio zum Beispiel,
VS Code oder so ist in den
Top 10, TensorFlow und so.
Das sind ja alles nur so mehr oder weniger Open-Source-Projekte.
Nicht so richtig eigentlich, aber Home Assistant schon.
Also ja, da geht auf jeden Fall
auch noch was. Und
ansonsten, ja, alles was irgendwie
noch so an
Server-Infrastrukturen automatisch hochziehen,
Deployment,
da ist Python auch sehr stark
vertreten. Das heißt, Web, hat man doch so ganz kurz gesagt,
ich glaube, ist gar nicht so klein, oder?
Nee, Web ist auch sehr groß, ja.
Also Django und Flask sind ungefähr
beide gleich groß, mehr oder weniger.
Und es sind beides
große Bereiche,
in denen es passiert.
Viele der Top-Seiten sind irgendwie
eins von beiden.
Also, genau.
Ziemliche Allround-Sprache eigentlich, kann man sagen.
Ja, okay.
Kann man fast alles mitmachen.
Was sollte man in Python können, um einen Job zu bekommen?
Hm, das, äh, hm, ich weiß nicht, also ich glaube, da kann man, das ist immer ein bisschen schwer, ne, wenn man das dann sagt, was Leute da machen sollen, und dann sagt irgendwie die Library oder das, das ist besonders interessant zur Zeit, dann braucht man irgendwie eine gewisse Zeit, um das zu lernen, wobei die meiste Zeit, die man braucht, um das zu lernen, wahrscheinlich dabei drauf geht, programmieren zu lernen, das dauert halt einfach lange, und dann ist es halt in dem Moment, wo man es kann, wieder veraltet.
Also insofern, das hilft alles nicht, aber ich würde sagen, tatsächlich die Geschichte, die am meisten bringt und von der aus man dann alle anderen Sachen, die man vielleicht lernen kann, ist halt tatsächlich einfach richtig programmieren können. Das ist schon so die Fähigkeit, die man haben sollte.
oder es ist halt auch etwas, was nicht so, es ist ja, ja.
Richtig programmieren können, das hört sich jetzt total einfach an.
Das hört sich total einfach an, aber das ist tatsächlich nicht so verbreitet,
wie man sich das wünschen würde.
Also das kann man immer, man denkt immer so, ja, das macht man halt irgendwie,
dann machen Leute irgendwie einen Kurs oder kaufen sich irgendwie,
ich weiß nicht, ob es sowas überhaupt gibt, Python in 21 Tagen oder Java.
Das geht nicht in 21 Tagen, das geht auch nicht in einem halben Jahr,
das dauert alles ein bisschen länger.
Ja, manche Leute denken ja, dass wenn sie die Syntax mal gesehen haben.
Genau, dass das das Gleiche wäre,
aber das stimmt halt nicht.
Die Syntax ist ja auch bei Programmiersprachen
eigentlich gar nicht so...
Also für Anfänger schon, die verstehen
erst mal überhaupt nicht, was da steht. Das ist der erste Schritt
zum Verstehen, worum es überhaupt geht.
Ja, aber wenn man das eben mit einer natürlichen Sprache vergleicht,
es gibt halt viel weniger Worte. Es gibt halt ein paar
ja,
es gibt ein paar
Verben sozusagen für Worte.
Hast du aber die ganze Standard-Library mit bedacht?
Klar, also die Libraries sind dann nochmal ein anderes Thema,
aber das muss man ja auch alles gar nicht so unbedingt
können.
Wenn man die Syntax und halt die paar
Worte, die es tatsächlich gibt,
kann, dann kann man das ja zumindest mal alles lesen.
Ja, also
das ist halt, also programmieren
können ist aber so ein bisschen wie ein Musikinstrument
können oder halt auch
Fremdsprache lernen oder so und das ist halt eine Geschichte,
die dauert einfach. Da gibt es
dann halt auch Sachen, wie man das schneller hinkriegt und
wie man das effektiver üben kann und so.
Aber
wenn man das dann kann,
dann kann man sich
eigentlich in jedes Thema relativ schnell
einarbeiten, würde ich jetzt mal so einfach sagen.
Und das ist halt
auch, denke ich, also die entscheidende
Geschichte, die man
können sollte.
Sich in Themen schnell einarbeiten.
Ja, beziehungsweise die Prinzipien des Programmierens.
Diese Geschichte, die halt lange dauert, halt schon
vorher erledigt haben, weil das
wird einem niemand gerne bezahlen wollen,
sondern das lernt man, das
lange dauert. Aber ich würde auch sagen,
da gibt es halt enormes Potenzial.
Jetzt hört sich so ein bisschen an, das kann das ja jeder,
aber das ist nicht so.
Also die allermeisten haben damit Probleme und strugglen da.
Und nicht die Mehrheit aller Programmierer
kann ordentlich programmieren, würde ich jetzt mal so sagen.
Ja, das musst du eigentlich noch definieren,
was denn ordentlich programmiert ist.
Und das ist vielleicht auch, das kann ich ehrlich gesagt
gar nicht so genau.
Und es ist auch die Frage,
eigentlich ist es auch wieder so ein bisschen,
ich will eigentlich niemanden ausschließen.
Ich würde sagen, ja,
selbst wenn man das nicht so total hundertprozentig kann.
Wahrscheinlich haben die meisten von uns
auch schon irgendwie Jobs gemacht, wo sie
dachten, dass sie dafür eigentlich gar nicht geeignet
wären oder so und das haben dann halt irgendwie gelernt.
So ist das halt auch
normal, das ist wahrscheinlich auch in anderen Bereichen
so und vielleicht
muss man sich einfach mal trauen, irgendwas zu machen
oder zu sagen, dass man irgendwas kann, auch wenn man es halt vielleicht nur so
ein bisschen kann und dann nicht so total perfekt.
Ja, aber du musst ja trotzdem damit rausholen,
was denn jetzt richtiges Programmieren dann überhaupt ist.
Also das ist ja zwar eigentlich jetzt nicht auf meiner Liste, aber dann musst
du jetzt in kleinen Kurvortrag teilen? Ich gebe dir sogar
zwei Minuten.
Naja, das wäre
gar kein Problem, das sind zwei Minuten, ist ja klar.
Also ich würde
sagen, wenn man halt
nichts total, also wenn man
Dinge so macht, wie sie gemacht werden
sollten, nicht so total schrecklich
Dinge falsch macht, vielleicht.
Weil tatsächlich ist es das, was man oft sieht, dass Sachen
halt wirklich, also nicht
nur so ein bisschen nicht ordentlich
sind, sondern so Kleinigkeiten, sondern
dass so Dinge so gar nicht richtig sind eigentlich.
Was gehört denn dazu, also was würde denn da?
Also ich würde sagen eben, dass
der Umgang mit den
ganz einfachen
Datenstrukturen, ja, also
irgendwie Listen,
Dicks,
irgendwie Skalare und damit halt ordentlich umgehen kann.
Also wenn man das schon kann, ist schon viel,
hat man schon viel,
weil das schon viele Leute nicht so richtig hinkriegen
und ja,
dann halt,
dass man eben
Sachen halt ordentlich in Funktionen packt,
nicht irgendwie Spaghetti-Gut schreibt, dass das halt alles so
halbwegs, sondern sich nicht
dauernd wiederholt. Dry, don't
repeat yourself.
Ja, aber da
gehen wir fast schon in diese Detailgeschichten,
oder dass man halt Tests schreibt und diese ganzen
Best Practices verwendet
und Versionskontrolle verwendet und so.
Mit den Daten schon, das musst du später nochmal sagen, da habe ich noch ein paar
Fragen, da müssen wir nochmal ein bisschen drauf eingehen, was denn
überhaupt jetzt im Skalar-Daten schon
was alles ist, ja.
Okay, also du sagst halt einfach, okay, man muss halt die Prinzipien
Best Practices irgendwie kennen und anwenden
und sich daran so ein bisschen hochhangeln und
irgendwie sich was besorgen, was man da...
Ja, und viel Code lesen, halt viel
sich mal angucken. Das Problem ist natürlich, wenn man
jetzt jemanden liest, wo du sagst, die Mehrheit der Programmierer
ist gar nicht so hervorragend
und dann lese ich jetzt von...
Ich würde es vielleicht anders sagen,
da ist viel Verbesserungspotenzial. Also wenn man sich anguckt,
was, wenn der Code, der geschrieben
wird von Leuten oder der so in Firmen
läuft oder so, ist das dann so, wie es
sein könnte oder kann da noch, geht da noch mehr?
Und da muss man sagen, da geht eigentlich
fast immer noch deutlich mehr.
Ja gut, aber wenn man sich jetzt seinen eigenen Code anguckt,
dann ein halbes Jahr später, dann denkt man natürlich schon so,
oh, was willst du sagen.
Ist das auch so, ja.
Genau, aber ja.
Ja, was, erstmal, also ich habe noch eine Basisfrage bekommen
vom Olli, der hat ja noch geschrieben,
Tipps für eine gute Syntax, dein Top 5 oder so.
Heute, heutzutage würde ich sagen, Black verwenden
und nicht mehr drüber nachdenken.
Also einfach Black, bumm.
Ja.
Vielleicht, also Namen vielleicht auch.
Namen sind natürlich, das ist eine ganz schwierige Sache, also wie kommt man da auf gute Namen, da muss man auch lange drüber nachdenken oft, also ja, da gibt es ja auch immer den bekannten Witz, was sind die zwei schwierigen Sachen, ja, in der Informatik irgendwie Dinge benennen, Caching und oft bei One-Error-Errors, ja, aber genau, also Dinge benennen ist schwierig, ist eine Kunst und ja, wo man sich da auch dran orientieren kann,
Ist so ein bisschen wie bei gutem Kommentaren.
Man sollte eher darauf achten,
hinzuschreiben, warum man das
macht oder was das macht. Nicht so
sehr, wie da irgendwas passiert oder so.
Ja, und halt dabei,
wenn man was schreibt,
dran denken, dass das,
wenn das jemand liest,
dann halt verständlich sein sollte, weil
Code viel öfter gelesen wird als geschrieben.
Ja.
Was ist mit sowas wie
List Comprehensions? Würdest du das bevorzugen,
gegenüber klassischen Loops.
Kommt drauf an. Also ich würde sogar
eher ein bisschen, die andere,
ich würde sagen, lieber eine
Vorschleife verwenden und
List Comprehension halt eher dann, wenn es halt
irgendwas einfacher ist, wo
ja, wenn es halt offensichtlich und einfach
ist, dann kann man auch gerne
List Comprehension verwenden. Aber wenn man
also, ich meine,
auch da,
das ist halt, wenn man irgendwas entdeckt, wie es
funktioniert und das dann cool findet, dann fängt man an, das überall
zu benutzen. Und ich habe dann auch schon
nicht List Comprehensions gebaut, irgendwie
wo ich dann halt
mehrfach verschachtelt irgendwie
über Dinge iteriert habe. Und das wird bei
List Comprehensions sehr, sehr schnell, sehr, sehr
unübersichtlich, wo ich dann halt irgendwie
stolz darauf war, so ein Statement hingekriegt zu haben.
Einer Zeile, Goldgolf.
Nicht in einer Zeile, das geht dann halt nicht mehr in einer Zeile, aber
dann so drei Zeilen List Comprehension
irgendwie mit Bedingungen drin
und verschachtelt und so lange
getüftelt, bis es irgendwie ordentlich funktioniert hat.
Das macht ja dann auch irgendwie Spaß. Das ist halt so ein bisschen
wie puzzeln, aber
ich fürchte, wenn da jemand dann draufguckt,
der das
verstehen muss und das unter einem gewissen
Zeitdruck tut, dann
würde der sich wahrscheinlich irgendwie
Rot vor Rot.
Spaß zur Ärger.
Da gibt es
das Remote Strangulation Protocol,
wie zu Hilfe wünschen.
Das Remote Strangulation Protocol?
Ja.
Ich weiß nicht.
Das kennt wahrscheinlich auch keiner.
Damals gab es so einen Text
auch schon lange her,
Bastard Operator from Hell
und da gibt es die
sysadmin, also es gibt die
sysadmin-man-pages oder die
sysadmin-recovery
gab es in Newsgroup
und dann
ASR, alt sysadmin-recovery
das war die Newsgroup und dann gab es die
ASR-man-pages und Tools
ich glaube, wenn man
man-asr sagt oder man-knife
oder man-snip oder so,
dann kriegt man das auch noch irgendwie
auf dem Linux zu sehen.
Da gibt es dann Tools, mit denen man
irgendwie Usern
die Attitüde
von Usern wieder
rejustieren kann. Und diese Tools sind halt
sowas wie Snip
oder Knife
ist da X.
Mit der Axt irgendwie mal dazwischen geht
und Dinge gerade richtet.
Die Attitüde von Usern regulieren, das hört sich
toll an. Ja, das klingt
nach Spaß an,
wenn man auf der richtigen Seite steht.
Ja, ist natürlich so ein bisschen, ich meine, das Mindset dahinter ist auch etwas fragwürdig, aber es ist damals irgendwie lustig. Und da gab es auch Protokolle und eines der Protokolle in dem Zusammenhang ist halt das RSTP, Remote Strangulation Protokoll über Fernverbindungen.
Sehr gut, das ist das, was man in Startorganisationen gerne hätte oder wo man dran arbeitet, das automatisch zu bekommen. Also ihr braucht gute Admins für den Start, damit das funktioniert.
Ja, also ein bisschen Syntax haben wir gemacht. Also die Frage wäre jetzt noch, was gehört als zu Python Fullstack dann? Also wenn man jetzt schon ganz viel kann und so, was würdest du sagen, wenn man richtig Fullstack entwickelt?
Ja, Fullstack, das ist so ein Ding, was heutzutage
auch wieder in aller Munde ist, wobei das
auch selten tatsächlich so ist.
Würde ich sogar sagen,
auch das, ich mach das nicht eigentlich.
Ich bin deutlich eher auf der Backend-Seite als auf der
Frontend-Seite, aber Fullstack hieße ja,
dass du quasi alles machen kannst, von
unten bis Frontend. Also Fullstack in Python
geht gar nicht, weil man kein Frontend kann. Das geht nicht richtig, genau,
weil du mit Frontend bist du halt nicht,
da brauchst du halt dann schon JavaScript
für und
ja, oder es ginge theoretisch
auch. Aber das ist halt ein Bereich, der schön wäre,
wenn das mit Python funktionieren würde. Aber momentan
geht das nicht richtig. Also man könnte natürlich Python
auch irgendwie Richtung WebAssembly
kompilieren und dann halt im Frontend verwenden.
Aber es gibt keine, es gibt
eben nicht so viel wie für JavaScript
die ganzen UI-Bibliotheken, die man
da so braucht, um halt Dinge irgendwie
auszumachen. Also
schwierig.
Ja, das heißt, JavaScript braucht ihr, wenn ihr Full-Tag
machen wollt. Und mit Python kriegt ihr das gar nicht so hin.
Aber vielleicht wollt ihr das ja auch gar nicht so machen,
weil warum sollte man Full-Tag machen, wenn man
die anderen Sachen wie Data und Backend so gut kann.
Naja, also wenn du eine Webseite machst, hast du
sofort diesen ganzen Kram, wobei du da
möglicherweise eben auch ohne JavaScript oder
ohne viel JavaScript auskommen kannst.
So eine ganz stinknormale
Webseite, so.
Ein bisschen CSS-Version machen
oder sowas, ja. Auch kein Python.
Auch wieder kein Python, genau.
Aber das geht natürlich auch immer noch und
ist eigentlich auch für viele Anwendungen
irgendwie gar nicht so schlecht.
Aber, ja. Ja, gibt ja so ein paar
Framework, ne? Grid, Materialize,
so. Naja, also ohne
JavaScript. Aber das ist ja was anderes. Ja, also Fullstack geht
gar nicht nur mit Python.
Und das ist tatsächlich auch einer der großen
Risiken
irgendwie für die Zukunft von Python, wenn das
halt, wenn das quasi so aus dem
Wettding, weil die Frage ist jetzt,
kommt Python nochmal ins Frontend oder
geht JavaScript ins Backend?
Und wenn der Weg in die Zukunft
so aussieht, das wird dann JavaScript, weil das natürlich auch
gewisse Vorteile bringt. Du kannst
einmal den Code, kannst ihn im Backend und
im Frontend verwenden.
wenn wir jetzt auch im Backend zunehmend
JavaScript kriegen, dann brauchst du halt
eigentlich Python in der Webentwicklung gar nicht mehr.
Oder es läuft umgekehrt
und wir kriegen auch irgendwann
Python im Frontend, das wäre natürlich eigentlich die schönere Variante.
Ja, da müssen wir mal dran arbeiten, dass das
passiert, das ist natürlich eine gute Sache.
Ich glaube, also die Chance ist gar nicht so schlecht,
also ich glaube, Python ist noch
bei Anfängern gerade ein bisschen beliebter, vielleicht bedeutet
das, dass das irgendwann dann auch in diese Richtung
driftet. Ja,
mal schauen, wer weiß.
Ja, noch ein Import-Sys.
Ja, ich glaube, das hatten wir letztes Jahr auch schon mal.
Ziemlich genau um diese Zeit hatten wir das nicht in der ersten Folge schon mal.
Am Schluss, glaube ich, ja.
Aber kann man sich auf jeden Fall immer mal wieder angucken.
Ja, also den Interpreter öffnen, einfach Import-Sys eingeben und abschicken.
Und dann seht ihr das.
Also die Prinzipien, die man sich darauf geeinigt hat,
die in Python gelten, sollen auch sein.
Da ist auch immer so ein bisschen Humor mit dabei.
Aber ja, ist auch was dran.
Ja, das ist direkt verknüpft zu PEP 8.
Ich glaube, das hatten wir dann auch schon mal kurz erwähnt, aber
an der Stelle vielleicht nochmal. Ja, das ist sozusagen einfach nur die
Art, wie man
relativ minimalistischer
Konsens darüber,
wie man Python-Code formatieren sollte
vielleicht.
Nee, wer macht das nicht, dann kommt hier in die
Python-Hölle. Ja, aber auch innerhalb
von Tab 8 gibt es ja so Dinge, die dann
nicht geklärt sind dadurch und
Black
hat halt zum Beispiel eben eine Meinung dazu, wie das
sein soll. Du kannst ja Dinge machen, die...
Ich finde bei einigen Sachen total furchtbar, das sieht scheußlich aus.
Okay, was denn?
Ja, wenn ich zum Beispiel Argumente in Funktionen packe
oder längere Print Statements schreibe,
wie er die dann umbricht,
dann macht er die Klammer auf in eine Zeile,
dann nächste Zeile den String aus dem Print Statement
und dann darunter die Klammer wieder zu,
wo ich dann sagen würde,
hey, für die fünf Zeilen,
wenn das Print Statement eh länger als 89 Zeichen ist,
hättest du das auch einfach in Einzel schreiben können.
Oder halt, wenn Kommentare am Ende der Zeile sind,
dann bricht er dann trotzdem die ganze Funktion auseinander,
obwohl sie noch reinpassen würde.
Oder wenn Black sagt, ganz viele Argumente in einer Funktion,
bricht das dann aber um, weil es nicht genug Argumente sind,
um auf jeder Zeile ein Argument zu haben.
Das sieht auch ganz furchtbar aus.
Und dann ist dann der, ich kann mal so mit dem Doppelpunkt,
dann am Anfang von einer Zeile irgendwie drei Zeilen Funktionsdefinition.
Das finde ich total furchtbar.
Ich bin eh nicht so ein Freund von diesem 89 Zeichen Editor-Quatsch,
weil ganz ehrlich, so entziehend,
dass wir nur 89 Zeichen auf dem Bildschirm haben.
79.
Entschuldigung, ich entwickle nicht die ganze Zeit
mit meinem Telefon.
Nee, das ist für Konsolen eigentlich.
Die haben halt bloß 80 Zeilen,
also 24 Zeilen,
80 Spalten.
es gibt natürlich, oder ich weiß nicht...
Ja, die alten, aber nur die neuen.
Weiß ich nicht, ob es dann...
Nee, der Standard ist immer noch so.
Es ist auch so, wenn du jetzt auf dem Linux oder so bist,
dann hast du ja nicht unbedingt immer ein grafisches System
und deine Konsole sieht halt so aus.
Da gibt es keinen...
Ja, aber auch bei VI hast du ja mehr.
Auf einer Konsole?
Ja, also ohne grafische Benutzeroberfläche, glaube ich, ist schwierig.
Aber auf der anderen Seite, wahrscheinlich gibt es diesen Fall,
dass jemand an einem Rechner ohne grafische Benutzeroberfläche sitzt,
praktisch gar nicht mehr so.
Also, wenn ich mich auf meinen Server einlogge,
habe ich da mehr als 80.
Ja, natürlich, aber du hast...
Über die Konsole, über meine Shell.
Hast du dich mal an eine Konsole gestellt,
an einem Rechenzentrum, an eine serielle Konsole?
Ich glaube, da hast du genau die 80 Spalten
und 24. Das ist ja uralt
DOS. Ja, bei DOS
war das auch so, genau.
Ja, ich
weiß auch nicht.
Also ich glaube auch nicht, das ist eigentlich nicht mehr relevant, aber
da kommt das halt her und
wenn, dann sieht man da halt, muss man kurz drauf aufpassen,
dass es dann umgebrochene Zeilen gibt,
die automatisch vielleicht eingeguckt werden
oder so. Ich weiß gar nicht, auf was ich es gestellt
habe bei mir. Das ist ja auch ein Ding, das man
bei Black tatsächlich einstellen kann. Also da
das muss man nicht
so auf 79 zeichnen lassen.
Also 79 Zeichen deswegen, weil man halt noch
eins braucht für einen Zeilenumbruch.
Aber
wenn,
also ich glaube, ich habe es auch irgendwo auf einer 10
stehen, aber ich weiß es nicht.
Jedenfalls, das kann man ja konfigurieren und dann ist es nicht mehr so schlimm.
Also ich finde auch ein bisschen mehr als 80 geht schon.
Irgendwann ist es natürlich auch wieder doof, wenn das
halt zu lang wird.
Also so, dass man es halt vernünftig auf einem normalen Arbeitsrechner
irgendwie vernünftig anlesen kann, dass es dann nicht immer halb so
groß ist, dass man viel zu viel Platz braucht.
Das wäre ja völlig unheimlich und hässlich, einige Sachen.
Also ich finde, DEC ist dann so ein bisschen inkonsistent,
wenn es halt dann,
beispielsweise, du hast drei Debug-Statements hintereinander,
das eine ist vier Zeichen zu lang, dann bricht
das ganz komisch rum irgendwie und die
anderen darunter sehen
nicht so aus. Das ist irgendwie komisch.
Naja.
Also ich finde das, wo mein ästhetisches Empfinden
wird, da immer so ein bisschen angehört. Naja, gut.
Wann ist man Amnesie-Syndrom erkrankt?
Ah.
Not invented hier, ja.
Das, äh,
Wenn man alles selber macht.
Sehr böse erwischt.
Ja, das ist halt das Problem.
Genau, das heißt einfach nur,
dass man halt versucht, alles selber zu machen.
Und wenn es halt nicht von hier kommt,
viele Firmen haben das auch, die ja alles
doof finden, was sie nicht selber gemacht haben und dann
halt viel zu viel selber machen. Das ist natürlich ein Problem.
Wir empfinden das Rad nochmal von vorn.
Genau. Das ist halt immer nett, da kann man immer was mit lernen.
Also die Grundlagen zu verstehen, ist gar nicht so schlicht.
Und hat man irgendwann nicht
kein mehr, der versteht, wie es irgendwann mal gebaut
worden ist, sondern nur noch Leute, die dann irgendwie
auf dem Sand und der Asche von alten
versunkenen Städten versuchen, neue Gebäude zu errichten
und dann immer so, oh, da war eine Grube.
Und dann steht es ja Palast
zusammen. Das ist natürlich dann das, was man vielleicht verhindern will
und deswegen ist das vielleicht auch gar nicht immer so schlecht.
Aber natürlich kann man ja viel Zeit damit
verschwinden, dass man einfach anfängt, komplett
das Rad nochmal neu zu erfinden,
obwohl man eigentlich schon irgendwie fliegen könnte, dann
naja. Ja, es ist
immer schwierig. Man muss da halt eine richtige
Balance finden. Es ist manchmal gut,
Dinge, also ein Beispiel dafür wäre auch
dieses Timestamp-Modell aus den
Model-Utils, ja, deswegen haben alle als Abhängigkeit
Model-Utils drin,
dabei, ja,
man ist dann auch so,
wie meinte ich, über Django 3 kurz
auch gesprochen
und da hat er dann so, naja,
das sind halt eigentlich zwei Zeilen,
irgendwie in einem Modell, wenn man das selber
macht, das ist,
vielleicht wäre es besser gewesen, die beiden Zeilen dann selber
hinzuschreiben und dann diese Abhängigkeit
nicht zu haben, weil jetzt hat man halt das Problem,
dass wenn man, das ist ja auch wieder
blöd, wenn man nichts selber macht,
ganz schlimmen NPM hat das ja auch so bei JavaScript-Geschichten,
dann hast du halt,
musst du dich halt
viel mit dieser Maintenance von diesem Kram
beschäftigen, was ja auch blöd ist.
Ja, Parkway-Resonierung muss immer stimmen
und genau in dem Zustand bleiben
und wenn du irgendwelche Bugs hast, musst du dann irgendwas updaten,
weil irgendwas kritisch war und das hat dann
andere Abhängigkeiten und dann fliegt dir irgendwas auseinander,
weil das inkompatibel ist mit irgendeiner neuen Implementierung
von irgendeinem, ja.
Also es ist halt auch, man kann nicht
sagen, das eine ist super schlecht, das andere ist,
sondern es ist halt, man muss halt irgendwie
da einen,
ja,
irgendwie einen Weg finden, der
für den Anwendungsfall, den man hat, den besten
Trade-Off bietet.
Aber tatsächlich ist es so, dass die
meisten Leute eher zu viel Richtung
Not-Invented hier gehen.
Ja, manchmal
ist das praktisch. Ich glaube, manchmal ist es auch gar nicht so
schlecht, wenn man einfach coole Sachen, die cool funktionieren, einfach benutzen
kann und die dann cool weiter funktionieren und
dann auch einem schnell irgendwas
ermöglichen zu entwickeln. Ich glaube, gerade für Anfänger ist das
gar nicht schlecht, wenn man halt nicht von ganz immer
anfängt, obwohl es natürlich auch nett ist, wenn man vielleicht
erstmal Assembler lernt und dann C und dann
guckt, wie es alles so funktioniert, aber es ist auch vielleicht ein bisschen
aufwendig. Man kann vielleicht auch ab und zu
mal eine High-Level-Bibliothek einfach benutzen,
um zu gucken, wie man Dinge damit anstellt, ohne
direkt alles zu verstehen oder selber zu
implementieren. Ja,
über die Zeit ist es natürlich so, dass auch
der Level an Abstraktion, auf dem man
arbeitet, wird halt immer höher eigentlich,
weil halt immer mehr wird Commodity,
also die Sachen, die früher
der interessante
Bereich war, in dem man irgendwas gemacht hat, die werden halt
zunehmend Community und
wandern halt sozusagen aus dem
interessanten Feld raus und das,
wo man die interessanten Sachen machen
kann, das geht über die
Zeit immer in abstrakter Geschichten. Das ist halt
auch die Frage, inwiefern das nicht unter Umständen,
also auf der einen
Seite kann man sagen, man kann heute mit viel
weniger Zeilencode irgendwie viel kompliziertere
Dinge und tollere Sachen bauen, auf der
anderen Seite ist es halt, wenn man sich das manchmal genauer anguckt,
es ist halt ein, steht das
alles so ein bisschen auf tönernen Füßen.
Es ist halt so Kartenhaus über Kartenhaus geschichtet
und irgendwie auf den unteren Ebenen
stimmen schon viele Sachen nicht mehr so richtig, aber dann
baut man halt so lange Abstraktionen drüber, bis es
wieder, also ja,
aber in Wirklichkeit hat man diese
Probleme nicht wirklich gelöst. Ja, wenn man halt das Gebäude
und den Palast aus der Samtgrube baut, man kann tatsächlich noch ein paar
Stahlträger einziehen, das dann zu tun hat, könnte der Palast
nicht mehr halten. Ja, das ist halt dann, ja.
Ja.
Aha.
Ja, aber jetzt gehen wir, glaube ich, jetzt haben wir so ein bisschen
generell darüber gesprochen, was so
Python generell, was das so ausmacht.
Jetzt gehen wir so ein bisschen tiefer in die
Probleme der, oder was heißt
die Probleme, die Ideen, die Konzepte der eigentlichen
Sprache, was man auch vielleicht achten muss.
Also, falls ihr noch Fragen habt, die ich nicht beantwortet hatte, schreibt uns
wieder, wie immer, hallo at pythonpodcast.de
Wofür ist die
InitPy?
Das ist eine gute Frage.
Ja, man braucht das irgendwie,
damit es ein
Paket ist.
Ein Modul, wo es
Unterschied zwischen Modulen und Paketen? Oh mein Gott.
Ich glaube, das muss ich ja selber nochmal nachlesen.
Damit der Namespace irgendwie vernünftig
zugegriffen werden kann. Also alles, was man da irgendwie reinpackt,
das sitzt dann im Namespace dieses Moduls, wenn man
es importiert, direkt drin.
Irgendwie so. Und dann kann man da direkt aktiv
drauf zugreifen. Aber die Frage ist halt, warum man
das dann nicht mit den Submodulen macht.
Du kannst das ja auch
reinschreiben,
was du exportieren willst, welche Symbole.
Interessante Frage ist,
kann man da auch Sachen ausschließen?
Also dass ich zum Beispiel sage, ja, auch diesen Modul bitte nicht
in den Namespace packen oder sowas?
Also es kommt noch
eine andere Frage von einem Hörer von uns, der
wissen wollte, wie das dann überhaupt so funktioniert, dass man
Module selber bauen kann. Ich glaube, das Einzige, was man machen muss,
ist halt ein Folder importieren.
Also indem man halt relativ
Zugriff drauf hat und dann einfach sagen
Import Foldername
oder sowas und wenn da eine Inispy drin ist, dann
kann man die Module, die da drin sind, einfach
aufrufen mit einem
Import-Teil und dann kann man
Modul, Verzeichnisname, Import, Python
Datei oder from Modulname
Punkt Python Datei, Import
Funktionsname und dann kann man
die einsetzen auf
dieser lokalen Ebene. Und die Frage wäre halt jetzt,
warum man diese initpy an der Stelle braucht
und was die halt vielleicht macht und
dass sie vielleicht halt dieses Namespacing,
was in Python auch irgendwie so ein Ding ist, also
zum Beispiel zu sagen, welcher Name
jetzt zu welcher Funktion, zu welcher
Sublibrary gehört,
dass das da ein bisschen definiert wird.
Ja, man kann auf jeden Fall an der Stelle kontrollieren,
was halt
eben, was mit welchem Namen
exportiert werden soll, sozusagen.
Und
dafür ist es ganz nützlich. Warum man sie unbedingt braucht,
weiß ich nicht so genau. Und das ist auch etwas, was
mir schon öfter mal auf den Fuß gefallen
ist und wahrscheinlich vielen Leuten, die jetzt,
dass man halt, kriegt manchmal so
wenig hilfreiche Fehlermeldungen, wenn man
die Init-Py vergisst,
sozusagen. Oder wenn die aus irgendwelchen Gründen abhanden
gekommen ist, was ja auch manchmal vorkommen kann.
Und dann kriegt man Tracebacks, die sehen
irgendwie komisch aus. Und man
sieht den nicht sofort an, dass da eine Input-Wire
fehlt. Irgendwann weiß man halt einfach so,
ah, das sieht jetzt danach aus, okay, das könnte sein,
dass da einfach eine Input-Wire fehlt, aber...
Ich hab zehn Minuten da vor meinem Bildschirm gestanden und überlegt,
warum macht der jetzt nicht die Migrationen von
meinem Dankmodell, den ich da geschrieben habe, verstehe ich nicht.
Und dann fehlte einfach die Input-Wire, Migrations-
Bruder und dann, ach so, ja klar, kennt der ja nicht,
kann der ja gar nicht sehen.
Aber da muss man auch drauf kommen, tatsächlich, sonst...
Ja, das ist so ein bisschen...
Genau, und eben, ja, also gute
Idee
mit, was sind eigentlich Paketemodule
wie funktioniert eigentlich ein Port-System?
Da müssen wir uns auch nochmal beschäftigen, aber da
müsste ich mich auch erstmal anlesen. Das weiß ich jetzt alles gar nicht so genau.
Ja, das kriegen wir bestimmt noch
jeden Tag. Aber wir haben ja die Minute schon wieder überschritten.
Ah ja, gut.
Aber Inipi ist ja immer mit dann, dann, also doppelt
Underscore am Anfang und am Ende. Also wofür brauchen wir
überhaupt ein Underscore und wofür zwei?
Ja, also ich glaube,
das ist...
Also die Konvention ist das.
Ich glaube, früher war es mal
nicht nur eine Konvention, aber mittlerweile ist es tatsächlich
nur Konvention, dass man Sachen, die halt
innerhalb einer
Klasse oder innerhalb
also Dinge, die halt sozusagen
private API sind oder privat
benutzt werden, aber nicht nach außen
eigentlich nicht von außen
benutzt, also
angefasst werden sollten, die
werden halt mit Doppel
und Underscore halt irgendwie gepräfixt
und Sachen, die halt
sozusagen
dann gibt es einfach ein Underscore, das ist halt
so markiert
für
Aber ja, also sollte man nicht, ist auch eher so interner Gebrauch, aber ist jetzt nicht so total privat.
Ja, also ist es eine Konvention. Im Grunde braucht man das auch, also außer jetzt manchmal bei Double Underscore, eigentlich auch nicht wirklich.
Also ich habe zum Beispiel diese internen Variablen
noch nicht verstanden, wofür das gut ist.
Ich habe es auch noch nie benutzt, außer jetzt
im Magic-Method-Kontext von
Klassen, wo man halt dann irgendwelche magischen
Methoden, die es identifiziert, überschreiben will, um
andere Effekte zu erzeugen.
Ja, es ist halt so ein
Hinweis darauf, dass man
da nicht
wirklich mit interagieren
sollte. Nicht umfassen, fast, meine Klasse
nicht. Alles, was man selber schreibt,
machen immer anders, bevor damit eigentlich niemand anderes
anfasst. Nee, nee, ich versuche
mal ein Beispiel zu geben. Also wenn du
eine Klasse hast, die irgendwas casht, dann
packst du halt
wenn, also du rechnest
das halt aus, du überprüfst in der Methode, ja,
sozusagen ein bestimmtes Attribut
ist eine Property von dieser Klasse,
also hat ein Property-Dekorator drüber, irgendwas
wird ausgerechnet und du
schreibst das Ergebnis dieser Berechnung, also prüfst
wenn du die Methode aufrufst, zuerst habe ich
das schon ausgerechnet, wenn ja,
gibst du einfach das
gecashten Wert zurück
und ansonsten rechnest du es halt neu aus,
unter bestimmten Bedingungen.
Und
den Cache selber, den legt man
oft dann in so eine Underscore irgendwie
Attribut ab. Underscore Cache.
Ja, oder Underscore
dieses, dieser Name, dieses
Attributes oder so, weil
und das heißt halt ja bitte nicht anfassen,
weil das Problem ist jetzt, wenn ich von außen da rangehe,
dann kriege ich vielleicht den gecacheten Wert, aber ich
kenne ja jetzt gar nicht die Bedingungen, unter denen das
vielleicht, ich denke, Cache invalidieren
müsste oder so. Und wenn ich da jetzt einfach so drauf
zugreife, dann
kann sein, dass Dinge schief
gehen. Und
das heißt, ja, das ist halt so eine Markierung
für, das Ding hier bitte nicht
direkt verwenden, sondern, ne, dann gibt's
ja meistens ein öffentliches
Attribut, was man
benutzen kann und dann kann die Klasse das intern
handeln, wie sie das integriert.
Was ist denn überhaupt eine API?
Ja,
im Grunde eine Schnittstelle,
die Schnittstelle zu irgendwas.
Das gibt's jetzt auch in unterschiedlichen
Kontexten kann man das
verwenden, aber ich würde jetzt mal sagen, also
üblicherweise, wenn man jetzt irgendein Paket
verwendet,
weiß ich nicht, Party-Django-Paket
oder irgendeine Python-Bibliothek oder so,
dann ist die API das, was
man sozusagen von außen benutzt.
Die besteht ja aus ganz vielen Funktionen.
Befehle, die man für seine Bibliothek benutzen
kann, um die
für den Anwendungsfall...
Also wenn ich jetzt zum Beispiel jetzt Requests nehme
oder so, dann macht
Request.get macht halt ein Get-Request, das ist halt
der öffentliche. Intern macht das dann
unter Umständen noch eine ganze Menge anderer Funktionsaufrufe
und Dinge und weißer Teufel.
Und die sind aber intern gar nicht alle
mit einem Underscore. Nö, also manche
von denen kann ich auch einfach so verwenden, das wäre auch kein Problem,
aber andere wahrscheinlich auch eher
nicht. Und die, die ich nicht unbedingt verwenden sollte
von außen, die sind halt dann
so markiert als
für intern gebraucht.
Was ist eine private und eine globale
Variable und was ist der Unterschied und wofür braucht man
Global, privat, also privat
öffentlich, das ist halt so ein bisschen, aber
das hat man in Python eigentlich auch gar nicht so wahnsinnig
viel, also es gibt es in anderen Programmiersprachen
gibt es da eine stärkere
Unterscheidung, aber also im Grunde
ist es einfach so. Also ich hatte es gerade so in den ganz
Anfängertagen ganz oft so, dass ich irgendwie mir dachte
so ja, private Variablen, das ist
alles irgendwie ein bisschen blöd, ich muss ja irgendwie von der Funktion
immer irgendwie so einen Wert returnen und damit das dann
also ich glaube im Kontext einer Funktion sind ja die eigentlich
die Variablen immer privat. Nein, nein, nein,
nee, das ist eine Verwechslung, also du meinst
lokal und global.
Privat und öffentlich, das ist
halt genau diese Geschichte mit dem Double Undersquad.
Ja, okay. Dann meinte ich lokal
und global, ja. Also
lokal heißt, Variablen sind halt
quasi in dem
Block
gültig.
Und ich
habe immer gehört, man braucht keine globalen, man darf
die nicht nehmen, dass das total nicht so backrest ist.
Kann man schon. An einigen Stellen habe ich halt
gemerkt, also gerade ich habe mal so Spielereien gemacht,
Spiele gebaut oder sowas. Da hat es immer total
super geholfen, weiß ich nicht, die Lebensenergie
des kleinen Männchens global
zu definieren, anstatt in einer Funktion oder so.
Jaja, kann man
durchaus machen. Es gibt auch Fälle, wo man das
durchaus
praktische Anwendungsfälle
hat.
Ist jetzt nicht unbedingt immer so gut. Also es kommt halt
darauf an, was man damit machen möchte.
Man muss das
halt explizit halt dann als
global markieren, wenn man das tun möchte. Und dann gibt es
auch, glaube ich, nochmal einen Unterschied zwischen
nur global oder global für ein
Modul oder
aber
ja, also für manche Sachen ist das
durchaus, also gerade irgendwelche Konstanten
oder so, die definiert werden, die sind oft global.
Also wenn man das nicht ändert,
ist das ja auch nicht schlimm. Wenn man jetzt globale
Variablen hat, die man ändert, dann
ist so ein bisschen
das riecht dann schon so ein bisschen danach,
als ob da irgendwas nicht so richtig ordentlich
funktioniert, weil
was
möchte man damit eigentlich machen? Also man hat
da irgendwie State, auf den man zugreift
von unterschiedlichen Stellen. Also es wird dann halt sehr schwer zu
debuggen und sehr schwer vorauszusagen,
was da eigentlich passiert, wenn man das einfach so verwendet
in unterschiedlichen Stellen des Codes.
Das dann ändert einfach so.
Da muss man sich halt sehr, sehr genau überlegen
oder man muss halt, also
vielleicht fange ich so rum an.
Das Problem beim Programmieren ist dann halt irgendwie,
dass ich an der Stelle, wo ich das ändere,
muss mir ja immer klar sein,
was an allen anderen
Stellen im Code,
an diesem Ding irgendwie rumgeschraubt wird, auch passiert.
Warum? Also ich nehme jetzt mal
so ein Beispiel, wo ich jetzt intuitiv sagen würde,
das wäre jetzt für mich das, was ich jetzt
als globale Variable haben würde. Ich habe
jetzt ein Spiel, mein Barbar hat Lebensenergie
von 100. Und es gibt
bestimmte Funktionen, die aufgerufen werden, wenn der
Barbar irgendwas macht, falsch macht, richtig macht,
runterfällt, gegen einen anderen, gegen einen Monster kämpft,
dann würde ich von dieser
globalen Lebensenergie irgendwas abziehen.
Ja.
Wofür muss ich denn dann an der einen Stelle,
wenn er jetzt, weiß ich nicht, auf ein Skelett trifft,
dem Zehn Lebensenergie abzieht,
wissen, was an einer anderen Stelle die Falle mit ihm gemacht hat.
Naja, also weil du, weil ja, naja, lass mal überlegen.
Kann ich irgendwas konstruieren, was dann problematisch wird?
Ich meine, es kann ja auch Dinge geben,
die die Lebensenergie wieder erhöhen.
Ein Trank.
Ja, und du musst halt zum Beispiel,
du musst halt wissen,
dass das jetzt schon nicht unter Null gefallen ist,
wenn du jetzt, sonst könntest du dich ja auch wieder lebendig machen,
sozusagen, wenn du tot bist, eigentlich.
Ein Lifehack, ja.
Irgendwas muss diesen State verwalten.
Irgendwas muss halt sagen, okay, jetzt bist du
aber tot. Und dann darfst du nicht
durch, darf nicht irgendein anderer Teil
des Codes, der jetzt nicht weiß, ob du tot bist oder nicht,
einfach deine Lebensenergie
oder deine Lebenspunkte erhöhen,
weil das macht dich ja eventuell wieder lebendig,
in einer Situation, wo das gar nicht gehen darf.
Also, sozusagen,
es ist... Also, das würde nicht so
gut funktionieren. Das heißt, da würde man auch auch
klassenbasiert einen Ansatz nehmen, wo man irgendwie
sowas machen wie erhöhe Lebenspunkte und reduziere
Lebenspunkte und der macht das halt dann nur dann, wenn man
noch nicht tot ist oder so. Genau, und das
erhöhe Lebenspunkte geht halt nur, solange man nicht tot ist,
zum Beispiel und so. Aber diese Logik,
wie das funktioniert, wäre dann halt an einem
Ort gebündelt. Das ist ja so ein bisschen die Idee
auch hinter Klassen,
überhaupt hinter Objektorientierter Programmierung,
dass du halt die ganze Komplexität
irgendwie verbirgst
hinter
ja, hinter dieser
in diesem Objekt, hinter einer API.
Genau, und dann das halt alles nicht mehr
wissen musst. Während wenn du jetzt einfach nur eine Variable hast,
die jeder irgendwie verändern kann,
dann ist die Komplexität verteilt
über den gesamten Code
irgendwie, der mit dieser Variable interagiert.
Was wäre denn jetzt aber ein cleveres Beispiel für eine globale
Variable, wo man sagen würde, hey, da macht das
irgendwie jetzt dann doch Sinn?
Mir fällt da fast keins ein,
wo das irgendwie sinnvoll ist.
Was man manchmal hat, ist, dass man
sicher sein möchte, dass
man etwas nur
einmal hat oder so. Aber da
würde man auch eher ein Single nehmen,
beziehungsweise in Python eher Borg-Pattern.
Oh, Singleton, das steht hier ein bisschen weiter unten.
Ein Singleton-Borg-Pattern, hast du gerade gesagt?
Ja, okay.
Was ist ein Singleton, was ist ein Borg-Pattern?
Du musst wieder anfangen.
Also sozusagen, Singleton ist, wenn garantiert sein soll,
dass es von einer bestimmten Geschichte nur eine Instanz gibt.
Also wenn ich zum Beispiel eben in einem Spiel die Spielfigur
oder so, die dann bestimmte Eigenschaften hat,
eben sowas wie Lebensenergie oder so,
wenn ich garantieren möchte, dass alle,
die damit interagieren, immer die gleiche Instanz sehen.
Dass ich halt den nicht, weil es gibt nur einen
und es wäre jetzt blöd, wenn ich zwei davon erzeuge und dann
in dem einen Objekt
verlinke ich die Lebensenergie und beim anderen nicht oder so.
Wie macht man das denn? Überschreibt man dann die New-Methode
und sagt dann so, nee, wenn es schon eins gibt, dann mach keinen neuen?
Naja, das ist, nee,
eigentlich, also so, weil
dann kommen wir zum Borg-Python, so wird das üblicherweise dann in Python
implementiert, ist, man macht
es einfach so, dass
jetzt muss ich mal,
wie ging das da? Also ich glaube, der Trick
ist, aber das muss man mal nachgucken,
also mit Vorsicht genießen,
ist, dass
sozusagen den State
innerhalb von der,
eines Objekts sozusagen
in der Klassenvariable zu halten,
die halt bei allen Instanzen gleich ist.
Und dann können die Instanzen zwar unterschiedlich sein,
aber der State ist immer gleich.
Und dann ist es zwar kein
Singleton in dem Sinne, wie
wie man das vielleicht ursprünglich mal so definiert hat.
Im Gänger-Vorbuch gibt es halt das Pattern Singleton,
weil man eben nicht immer tatsächlich,
also ich glaube, bei ursprünglichen Singleton-Beschreibungen
ist es so, das wird einfach immer die gleiche Instanz returnt,
wenn man halt die...
Also das heißt nie überschreiben.
Das würde halt bedeuten, wenn es schon ein anderes gibt,
dann returnt es halt das.
Returnt so das alte halt.
Sowas kann man auch in Python machen, das wäre kein Problem,
aber praktischer ist es halt, weil es einfach weniger Code
und macht sozusagen, verhält sich ähnlich
und hat noch ein paar andere nette Vorteile.
dass du halt sozusagen sagst, der State
bleibt über alle Instanzen
von diesem Objekt gleich und ich muss da nicht kompliziert
irgendwie dafür sorgen, dass ich immer die gleiche Instanz zurückgebe, weil
wen interessiert es?
Ja, aber genau, das sind alles,
es geht immer so um State Handling im Grunde, das ist immer so,
und wer manipuliert den und wie kann man dafür sorgen,
dass man
den Code, der den State manipuliert, an einer Stelle behält
und so und nicht, weil das sind immer so
das ist was, was halt man am Anfang
das ist ein bisschen unintuitiv, das
denkt man sich so, naja, das ist ja kein Problem
State kann irgendwo sein, egal
ist in einer Variable, in einer globalen Variable
oder so oder halt auch
oft verteilt oder man hat
die Klassen, sich mal irgendwie überlegt, wie
so eine Klassenhierarchie aussehen soll
oder so, aber
zieht das dann durch, unabhängig davon, wie das Problem
eigentlich ist und
das fiese, was manchmal dann
oder fast immer passiert, irgendwie
ist, dass man dann halt den State verteilt
über viel Code.
Was ist überhaupt State?
Das, was du
speichern musst, was sich
irgendwie ändert.
Der Status.
Also
sagen wir mal so, bei einer Web-Applikation würde
man sagen, das ist der State einer Web-Applikation,
liegt üblicherweise dann eben in der Datenbank.
Das ist so einer klassischen
Datenbank.
Was bedeutet das? Also was ist
denn überhaupt dann der State? Sagt
der, wie der
Nutzer gerade aussehen soll, wie der heißt
und was er für Daten gespeichert
hat für sein Profil, was
er sehen soll. Und das ist halt nicht dynamisch
generiert, sondern das liegt dann irgendwo rum.
Das heißt, wenn man das ändern
möchte, dann muss man erst die Daten anfragen oder so was.
Das macht man dann gar nicht woanders.
Ja, genau.
Also
das, was halt sozusagen
beschreibt, in welchem Zustand
deine Applikation ist.
Gehen wir jetzt nochmal aufs Spiel kurz, also was
mit der Figur ist, was hat die gerade für eine Waffe
in der Hand, was für Lebensenergie hat die, wie viel
Rüstung hat die noch an, das wäre der State.
Genau, dann gehst du irgendwo in einen virtuellen
Laden und kaufst dir irgendwie das magische
sonst was Schwert, Feuerschwert, mit dem
du irgendwie alle platt machen kannst, dann muss
ja irgendwo gespeichert werden, dass du das jetzt
hast, dass das deine Adventure ist. Und ich darf aber auch
keine zwei gleichzeitigen Sachen dann irgendwie
haben, also damit das sich jetzt nicht widerspricht, darf es immer noch
ein State geben, das so das, was
dahinter steckt. Die interessante Frage ist, wie
verwaltet man diesen State?
sozusagen. Und
naiv
wäre halt, man hat
halt zum Beispiel, Held da ist halt in irgendwelchen
globalen Variablen. Man hat halt eine Liste,
die ist halt global,
genau, da steht halt drin,
ja, hier ist halt das Flammenschwert
und das ist da jetzt in dieser Liste der
Items drin. Und alle manipulieren
diese Liste von Items irgendwie.
Aber das macht dann halt Probleme,
weil dann ist Logik, die jetzt
irgendwie solche Sachen
abbildet, wie das Flammenschmerz
macht jetzt plus 10 Angriff, aber
auf der anderen Seite wird dir heiß, das heißt
wird dir die Hand heiß und
du verlierst irgendwie alle halbe Stunde ein paar Lebenspunkte
oder sowas, keine Ahnung.
Das ist ja Code,
der irgendwie diese Business-Logik,
wenn man das so sagen kann, in dem Spiel
halt implementiert und das kann ja sein, dass da
unterschiedlicher Code an unterschiedlichen Stellen steht
und wenn du jetzt überall das gleiche
globale
Variable hast,
auf die du zugreifst, da musst du dafür sorgen,
dass dieser gesamte Code, der halt
über dein Projekt verteilt sein kann,
dass der immer weiß, was alle anderen Sachen
machen. Und das geht ab einer gewissen Größe nicht
mehr. Am Anfang geht das, solange es alles sehr klein
ist, kriegt man das auch noch hin, dass man
das alles im Kopf behält. Ja, du musst halt jedes Mal zumindest
diese Überprüfung machen. Du musst halt jedes Mal gucken,
hat denn jemand irgendwas geändert an der Stelle, das nicht sein
darf. Das heißt, jede dieser Logiken müsstest du
bei jeder Stelle, wo
diese globale Variable geändert wird,
erneut machen, was halt dem Don't Repeat Yourself
widerspricht und so.
das kann schon durchaus so sein,
dass man sich da nicht wiederholt, aber
du kannst halt Änderungen machen,
die dann nicht lokale Auswirkungen haben.
Also nehmen wir an, du weißt das halt alles
nicht. Du machst jetzt halt ein neues
Item, sozusagen, das irgendwelche
Spezialgeschichten hat, schreibst da Code für,
dass das halt irgendwie tut
und dabei bedenkst du aber nicht,
dass unter bestimmten Umständen
irgendwelche Anarchoid irgendwas anderes tut.
Und dann passieren halt Fehler
und seltsame Effekte und
solange man halt von dem
ganzen anderen Code, der irgendwie daran rummanipuliert
irgendwie weiß, ist das ja okay, aber
sobald das Projekt irgendwie größer wird, geht das
irgendwann nicht mehr und dann
kann man überhaupt nicht vorhersagen, was passieren
wird, wenn man jetzt irgendwie
Dinge ändert, wie man manipuliert
irgendwas an den Lebenspunkten oder so und dann
gibt es irgendwas anderes, was wiederum nochmal was anderes
macht. Der Invincible
Geist. Ja, und
das Mittel dagegen ist halt,
dass du eben nicht direkt
die Daten pro anfasst,
sondern, dass du sagst,
okay, wir haben hier eine Klasse oder so
und der ist, bündeln wir den State, also die Daten
und die Logik, die jetzt irgendwas damit macht
und haben da eine API nach außen, die öffentlich ist
und können sozusagen immer überprüfen,
dass alles ordentlich ist an einer Stelle.
Ja, die Frage war, was ist ein Objekt in Python?
Was ist ein Objekt in Python?
Ich würde es jetzt mal sagen,
das erklärt aber nicht viel,
ist halt die Instanz,
konkretisierte Instanz von
irgendwie einer Klasse.
Also
in einer Klasse definiert man sozusagen
irgendwie, ja,
eben eine
Zusammenfassung von irgendwie Code, der was
tut und irgendwie Daten,
die man irgendwie halten will und
wenn man das jetzt, das ist halt sozusagen
die Beschreibung
und wenn man da jetzt daraus...
Ich sag nicht so besonders an von dem Brot, der irgendeine
Beschreibung von irgendwelchen Sachen...
Ja, also man könnte das vielleicht
also... Also ein Objekt
ist ein Ding. Also ich glaube, in Python ist alles ein Ding
oder ein Objekt, oder? Alles ein Objekt, ja.
Also alles, was es in Python gibt, kann sich
als Objekt darstellen. Also ein Objekt ist immer
eine Instanz einer Klasse,
wenn man das so sagt. Ja. Das heißt,
alles, was ihr habt in Python, sind tatsächlich
Instanzen von irgendwelchen Klassen, von irgendwelchen Dingen.
Ja. Die nächste Frage
war, was ist Self? Self ist immer
das Objekt selbst, also wenn man in dem Objekt
auch eine, ist eine Konvention sozusagen, dass man
das so nennt, aber
sehr sinnvoll, das so zu machen.
Außer es gibt wiederum Spezialfälle, bei denen
man das ein bisschen anders macht. Also wenn man
eine Methode hat, also Methode ist nichts
weiter als eine Funktion,
die sozusagen an so ein
so eine
Instanz, an so ein Objekt gebunden ist.
Und jetzt
möchte man halt, um zum Beispiel auf die Daten,
die man halten möchte, in so einem Objekt
um da drauf zuzugreifen, muss man
ja irgendwie sich selbst referenzieren können
deswegen wird immer als erstes Argument in Methoden
das ist halt auch das
was dann Methoden von Funktionen unterscheidet
immer eine Referenz auf
das
auf sich selbst sozusagen mit übergeben
man könnte das auch anders nennen
man kann auch sagen
A statt Self, dann ist es A
aber es ist schon sinnvoll das Self zu nennen, damit man weiß
dass es halt eine Referenz auf
sich selbst ist, sozusagen auf das Objekt
was gerade, was man gerade ist.
Und dann kann man halt auf Self-Punkt
irgendwelche Daten zugreifen.
Da fangen wir jetzt direkt ein paar andere Sachen ein,
weil wir jetzt gerade so hatten mit Objekt.
Was ist denn ein Objekt? Es ist eine Klasse und jetzt gibt es
irgendwie drei Dekoratoren, also wir müssen noch gleich
darüber sprechen, was ein Dekorator ist,
aber es gibt drei Dekoratoren, die Python
verwendet, die da immer so drüber
stehen. Static Method, Class Method
und
Property. Über Property hattest du eben auch schon.
Was ist denn jetzt da irgendwie
so der kleine
Hagen, also wann
dachte man jetzt zum Beispiel, das ist eine statische Methode
und wann dachte man, das ist eine Klassenmethode?
Was heißt das denn in dem Kontext zu Self und
Objekt und
Ja, also ich würde eigentlich
am liebsten mit der
Klassenmethode anfangen, also
Class Method
ist halt eine
eine
Methode, die eben nicht eine konkrete
Instanz, das heißt da fehlt auch
Self bei der, genau, da könnte man
jetzt auch Self übergeben, das wäre dann sehr verwirrend
sondern was man da üblicherweise
übergibt, ist ein CLS
oder so und bekommt man die Klasse übergeben.
Die Klasse ist auch wieder ein Objekt.
Das ist auch irgendwie, man kann das dann noch ein Stückchen
weitertreiben, auch dann mit dem Meta-Klassenanschluss.
Also die kleinste, das kleinste Objekt, also
jede Klasse ist irgendwie ein Objekt und das Objekt
Objekt und Objekt selber ist ein Objekt vom Typ-Typ.
Ja, okay.
Ja, okay.
Ja, also
jedenfalls
in der Klassenmethode
übergibt man halt CLS und nicht
Self, weil man damit halt weiß,
dass man jetzt gerade die Klasse in der Hand hat und nicht
eine Referenz
auf die Instanz.
Und es gibt
halt, das verwendet man vor allen Dingen dafür, dass
man, es gibt halt bestimmte Methoden,
die brauchen eben nicht, die müssen nicht
auf irgendwelche internen Daten oder so zugreifen,
weil die hat man ja nicht.
Sondern die machen halt,
die gehören zwar vielleicht irgendwie in die
Klasse rein, weil die Funktionalität,
die sie bieten, halt sehr viel zu tun hat mit der
Klasse, aber die
verhalten sich in gewisser Weise natürlich dann so
wie eine normale Funktion.
Und vielleicht können sie auch
auf Daten, die halt
für alle Instanzen dieser Klasse
gleich sind, zugreifen eben über die Klasse, aber
die brauchen
jetzt nicht
irgendwie eine konkrete
Instanz, auf der sie irgendwas machen. Also Beispiel
für
sowas sind, was ist denn ein gutes
Beispiel für
aus dem Spiel, also
zwei Beispiele, die ich ganz gut zu visualisieren
finde, entweder hat man so ein Spiel mit so
Charakteren oder man hat so ein
Universum mit Planeten und Dingen, die umeinander
kreisen oder sowas. Zwei verschiedene
Sonnensysteme als zwei Klassen.
Okay, lass mir das.
Ich weiß nicht so genau, ob ich das da irgendwie, also
mir fällt da jetzt gar nichts
also es sind oft
irgendwelche Hilfsfunktionen oder so, die
was machen, was logisch dann
in der Klasse gehört, aber wo man nicht mit einer konkreten
Instanz irgendwas zu tun hat
mir fällt jetzt tatsächlich kein super tolles Beispiel
Was ist denn der beste
Static Method, was wäre das denn jetzt so als
Ja, Static Method
Die bekommt halt einfach
tatsächlich überhaupt nicht mal die Klasse.
Aber im Prinzip ist das nichts anderes,
außer dass sie nur nicht mal die Klasse bekommt.
Das heißt, sie könnte man auch
draußen hinschreiben. Genau.
Der einzige Unterschied bei der StaticMethod ist halt, dass sie dann
im Namespace der Klasse
oder des Objekts aufrufbar ist oder so.
Ja, was ist jetzt in dem Vergleich eine StaticMethod?
Okay.
Ja, also StaticMethod
bekommt gar kein
automatisches Argument
mit, sozusagen.
Das wäre dann die reine,
wäre quasi wie eine Funktion, ja, also es ist
egal, ob man jetzt Static-Method
aufruft oder halt
eine Funktion von draußen, genau.
Ah, richtig, jetzt fällt
mir doch wieder ein Beispiel ein zu Class-Method, wo das
wenn man jetzt
in Django zum Beispiel Modelle hat,
dann sind halt
viele Geschichten,
die jetzt ein Modell betreffen, die man von außen
aufrufen kann, ruft man halt auf der Klasse auf
und nicht auf einer Instanz, weil eine konkrete
Instanz ist ja zum Beispiel,
man hat ja die Daten für,
die Geschichten stehen halt
in der Datenbank
und jetzt eine konkrete Instanz
eines, also Django-Modelle
sind Klassen
und sie modellieren sozusagen
den Zustand, der irgendwie in der Datenbank steht
und eine Instanz
üblicherweise ist halt
eine Zeile, also wenn ich jetzt zum Beispiel
ein Beispiel User nehme, ja, also ein User-Objekt
in Django ist halt
eine Zeile aus der Tabelle
Users irgendwie und
hat halt all die Attribute,
die jetzt irgendwie die Zeile hat, also
Spalten hat sozusagen in dieser Tabelle.
Ja, aber ich
möchte jetzt möglicherweise Dinge machen
auf der kompletten Tabelle.
Auf allen Nutzern. Ja, genau, auf allen
Nutzern oder ich möchte einen neuen Nutzer erzeugen.
Ja, das kann ich ja jetzt nicht innerhalb
von einem Nutzer machen, sondern das ist halt
irgendwie, ja, und dafür
sage ich dann
irgendwas, Users.Objects.Create
und das ist dann halt eine Class-Method,
die zwar sozusagen
ja, Informationen über die Klasse braucht
und wissen muss, was man dann so tut.
Also Users.Create. Streng genommen ist es
naja, Objects.Create ist halt
der Model-Manager, auf den man das aufruft,
aber das ist halt dann ein Ding,
aber dieses Objects ist halt... Ja, den Manager lassen wir jetzt mal kurz
weg, da müssen wir uns schon ein bisschen zu sagen gehen. Ja, es ist nochmal
komplizierter, aber dieses Objects ist auf jeden Fall
Dingen, was an der Klasse hängt
von
ja, was halt sozusagen
also man kann sich das so vorstellen, es betrifft halt
die gesamte Tabelle, man erzeugt jetzt auf dieser Tabelle
eine neue Zeile und das kann nicht eine Methode
sein, die man auf einer Instanz aufruft, sondern
die halt Instanz und die eine Zeile repräsentiert, weil innerhalb
von der einen Zeile sich selber irgendwie
ranzeigen würde, gar nicht so richtig funktioniert. Ja, könnte man auch machen,
wäre irgendwie komisch. Und warum
nimmt man jetzt aber dafür jetzt nicht einfach eine Static-Method?
Ja, könnte man auch, aber, nee, kann man nicht,
weil dann würde man halt zum Beispiel nicht mehr wissen,
was sind denn jetzt die ganzen Felder.
Wie der Kontext von der Tabelle wahrscheinlich.
Genau, man möchte ja auch wissen, welche Attribute gibt es,
was muss ich eigentlich da, und so, das, ja, das muss man ja auch,
welche Tabelle ist denn das überhaupt, wo steht die in der Datenbank,
und das hängt halt an der, das sind Informationen,
die an der Klasse dranhängen, und, ja.
Das heißt, die Static Method würde mir sowas sagen,
wie ist da draußen denn was anderes noch verfügbar,
das könnte ich dann vielleicht gucken.
Static Method könnte sowas sein wie
hash mir mal das Passwort.
Also hier hast du einen String, mach mir mal einen Hash davon,
den ich dann irgendwie in die Datenbank schreibe.
Das braucht gar keinen Kontext.
Das nimmt irgendwie einen String und gibt einen anderen String raus.
Das braucht aber sonst überhaupt nichts zu wissen.
Und das könnte dann ein Static Method
sein zum Beispiel. Aber es gehört halt logisch
vielleicht schon in die User-Klasse, weil es halt
irgendwie um Passwörter geht, die
ein User eingibt und die dann halt irgendwie
gehashed werden sollen.
Jetzt haben wir noch Property.
Property-Dekorator, ja, der ist
da geht es eigentlich nur darum,
dass man
ja, so ein bisschen Convenience, dass man
nicht eine Methode aufruft, sondern
also man schreibt halt
also der häufigste Fall ist, man hat
eine Methode, die nennt man so wie
ein Attribut und schreibt dann addProperty drüber
und dann
wird halt diese Methode aufgerufen,
wenn man irgendwo sagt Instanz.
Also braucht man eigentlich nicht, man könnte auch
eine Methode schreiben.
Ja, aber dann müssen wir halt dann an der Stelle, wo man es
verwenden will, Klammer auf Klammer
zusagen, was halt so ein bisschen sinnlos ist,
wenn man zum Beispiel gar nichts übergeben möchte
an Argumenten und
vielleicht auch etwas ist, was halt
so aussehen soll, als wäre es ein Attribut,
aber wo man Sachen noch ausrechnen will
und dann kann man halt den Property-Dekorator
benutzen, um halt...
Oh, das ist quasi ein getarntes Methodending.
Ja, ist so manchmal ein bisschen,
also das ist auch so,
diese Dekorator-Geschichte
ist so manchmal ein bisschen,
also
auf Python steht ja sowas, explizit ist besser
als implizit. Und das ist halt schon ganz schön
implizit, dass wenn man jetzt irgendwo
eben
Instanz
x.huber sagt, halt dann
irgendwie Code ausgeführt wird, der irgendwas ausrechnet
und dann unter Umständen auch sehr langsam sein kann.
Das ist halt nicht unbedingt, also in dem Moment, wo man
das halt lokal liest,
weiß man nicht, was passiert. Was immer so
ein bisschen schlecht ist. Aber
ja, es ist eigentlich
normalerweise, wenn man dann komplizierte Sachen
macht, dann sollte man das vielleicht dann auch eher
als Methode hinschreiben und dann
wird das dann vielleicht klarer.
Aber wenn man kurz vielleicht zwei Attribute
hat, wie das eine ist Kosten, das andere
ist Umsatz und dann will man den
Gewinn ausrechnen, dann kann man vielleicht schon eine Funktion
machen, die dann einfach kurz als
Property sagt, hier gibt man Umsatz
gewinnen und dann geht das einfach schnell aus.
Und ja, also
das Get
zu implementieren ist sehr leicht, man schreibt irgendwie
der Property drüber und dann war's das. Das Set
geht auch, also man kann das auch so machen, dass dann halt ein Setter
aufgerufen wird, wenn man sagt,
Instance x.fuba gleich irgendwie.
Das ist ein bisschen komplizierter,
aber, tja, geht auch so ähnlich.
Ja,
also man kann, ich weiß nicht genau,
man kann mit dem Property-Dekorator irgendwie sagen,
das ist hier der Getter, das ist hier der Setter oder was.
Ach, ich weiß nicht genau. Man kann dann nachgucken, wenn man es braucht.
Braucht man selten. Also ich
habe es ein paar Mal benutzt, aber nicht oft.
Aber überhaupt das
Konzept von Dekoratoren.
Getter-Setter bedeutet halt, dass man die Attribute irgendwie
von außen dann beeinflussen und setzen.
von der Instanz setzt,
bekommt oder setzt,
genau, und zwar nicht direkt manipuliert, sondern
halt Methoden
dafür aufruft, die dann noch irgendwas vorher und hinterher tun.
Jetzt haben wir schon ungefähr 50 Mal Dekorator gesagt und du wolltest
da nicht noch irgendwas anderes vorher sagen.
Dann muss man vielleicht nochmal erklären, was ein Dekorator eigentlich ist.
Eigentlich ist es eine sehr,
eigentlich nicht so,
es kann
leicht kompliziert werden.
Ja, es ist
auf der einen Seite ein bisschen Spezial-Syntax,
Diese Geschichte mit dem Ad-Symbol, dass man halt über Klassen und über Methoden, Funktionen schreiben kann.
Auf der anderen Seite ist es, man könnte es auch anders hinschreiben.
Da bräuchte man diese Spezialsyntax nicht, also die einem das so ein bisschen vereinfacht.
Man könnte halt auch hinschreiben, irgendwie x gleich, wrap mir mal eine andere Funktion, wrap, Klammer auf, irgendwie eine andere Funktion, Klammer zu.
Und dann wäre das die dekorierte, wäre x die dekorierte Funktion.
Und man macht sich eine Tapete auf die Wand und unter der
sieht man dann halt hier Sachen anders.
Ah, die Form bleibt erhalten, aber die ist dann
vielleicht rot oder blau.
Ja, also die Idee ist sozusagen, dass man
etwas
macht, also man halt Code hat, der
ja, man packt,
deswegen ist Dekorator eigentlich auch
und das zeichnet ziemlich genau, was es tut.
Man hat halt...
Input und Output, der rauskommt oder
reingeht, wird...
Geht nochmal durch anderen Code durch und dann
sozusagen, man kann halt
bevor irgendwas, bevor die Funktion aufgerufen
wird, irgendwie Dinge damit tun und
hinterher Dinge mit dem
Das wird aber ganz schön langsam, wenn das durch einen Dekorator
hat, der einen Dekorator hat, der einen Dekorator hat, dann
Ja, aber normale
Funktionsaufrufe macht man
ja auch, ist auch okay, also
und das ist ja auch nichts anderes im Grunde. Das heißt, wenn man
einen Dekorator selber schreibt, dann baut man quasi einen eigenen
Rapper und sagt halt, was passiert, bevor der da reingeht und
wann der wieder rauskommt.
Ja, man sollte auch
tatsächlich
nicht wirklich, wenn man Dekoratoren
schreibt, nicht das selber machen,
sondern man sollte für den Functools
Wraps oder so nehmen.
Und weil es gibt
noch so ein paar Hakeligkeiten mit den
Funktionsnamen zum Beispiel, die sonst verschwinden,
wenn man, die sieht man in Tracebacks nicht mehr
und da muss man so ein bisschen, und dann gibt's
halt eben in den Functools
gibt's da glaube ich
irgendwie
Funktionen, die, wenn man die benutzt, um
einen Dekorator zu bauen, dann kümmern die sich um diesen
Kram, sodass halt dann man in Traceworks weiterhin
die Namen sieht und so. Also das ist ein bisschen...
Was hat denn das jetzt mit so einem Kontext zu tun? Kontextmanager oder so?
Oh nee, das hat aber nichts zu tun.
Das ist eine andere Geschichte.
Das hört er sich so ein bisschen an, als macht man irgendwie so einen Kontext auf und
rappt irgendwas und baut das dann am Ende
wieder auseinander.
Also
ja,
also was eventuell irgendwie
eine Gemeinsamkeit
ist, dass beides irgendwie unten drunter vielleicht
Closure ist verwendet, weil es, wie das
umgesetzt ist, aber
das ist sozusagen
eine interne Funktion, die halt
zurückgegeben wird
und
die halt, das ist ja auch so der Trick, wie man das hinkriegt,
dass der Scope,
dass man halt auf die Sachen zugreifen kann,
die im Scope der Funktion sind,
dass man halt sozusagen,
naja, das ist zu kompliziert,
das kann man alles nicht so, das ist auch nicht entfängermäßig,
das kann man nicht gut erklären, da muss man sich einfach mal,
also ich würde sagen, also ein Tipp ist,
und wenn man Dekoratoren schreiben will, aus den Functools die Wraps-Funktion zu nehmen
und einfach mal so ein bisschen damit rumzuspielen.
Man braucht ein bisschen, bis man das so raus hat.
Aber dafür sind Dekoratoren da.
Man kann damit ganz nette Sachen machen, wie zum Beispiel,
also wenn man einfach nur wissen will, wofür braucht man solche Sachen eigentlich.
Wenn man, ja zum Beispiel eben wieder Datenbankgeschichte, kann man sagen, okay, gibt es einen Transaktions-Dekorator, da schreibt man einfach drüber.
A Transaction Atomic.
Genau. Das hier ist jetzt alles in einer Transaktion und alle Schritte gehen zusammen gut oder gar nicht. Und wenn halt zwischendurch irgendwas nicht funktioniert hat, dann rollt das automatisch die Datenbank in den ursprünglichen Zustand zurück, als wäre nichts passiert.
Das ist ein tolles Beispiel, weil da gibt es nämlich auch den Kontextmanager, man kann auch sagen, with a Transaction Atomic.
Ja, ja, ja, genau. Klar, kann man auch machen. Das ist eine Geschichte. Ansonsten, man kann auch Dekoratoren dafür benutzen, um sich jetzt eine bestimmte Datenbankverbindung immer reinzuholen in eine Funktion.
Ja, da werden wir jetzt gerade über Tango reden.
Da wird das ja auch benutzt, zum Beispiel, um Funktionen zu dekorieren.
Login required, dass man halt irgendwie eingeloggter Benutzer sein muss.
Das heißt, die Frage ist halt, was er dann macht.
Das kann man auch als Mixin benutzen.
Das heißt, auch das wäre eine ähnliche Methode.
Ein Mixin ist eine Subklasse, eine Klasse, die man benutzt,
um bestimmte Attribute zusätzlich dazu zu packen.
Mixin sind so ein bisschen eben, wie man Code wiederverwenden kann,
in Klassen ohne erben zu müssen.
Weil Erben macht natürlich das ganz klassische Weg und das kann man natürlich auch tun.
Ja, also in gewisser Weise ist es ja eine Form von Vererben, aber eine generalisierte Form, die irgendwie jetzt nichts genau mit der ursprünglichen Klasse zu tun hat.
Ja, genau. Also du kannst halt, ist es nicht so, dass du, ja, also zwei unterschiedliche Klassen, die nichts miteinander zu tun haben, ganz unterschiedliche Stellen in der Klassengereiche sind, können halt das gleiche Mix-In verwenden.
Cool, das ist so ein bisschen wie Genetik. Du kannst dem Frosch Flügel geben oder so.
Ja, warum auch nicht?
Ja, wenn man die Flügel haben will,
man hat irgendwie eine Klasse, die Flügel bereitstellt,
dann kann man diese Flügel jeder Klasse geben.
Ja, macht natürlich auch nicht immer Sinn.
Aber also Vererbung ist auch so ein problematisches Gefühl.
Das ist immer das, was einem,
wenn man sich mit objektorientierter Programmierung beschäftigt,
irgendwie so gesagt wird, wie man das tun soll oder so am Anfang.
Keine Ahnung, jedenfalls bei mir ist es mittlerweile auch besser geworden,
dass man halt Sachen von Dingen dann erbt,
dass man halt, keine Ahnung,
ja, weiß ich nicht, da wird immer mit
solchen Beispielen gearbeitet,
was
dass man
irgendwie, keine Ahnung, meistens irgendwelche geometrischen Formen
oder sowas, irgendwie, wenn man
jetzt ein rechtwinkliges Dreieck hat, dann ist das
auf jeden Fall schon mal ein Dreieck und ein Dreieck
ist irgendwas, was halt irgendwie...
Ja, ich finde das gar nicht so schlecht, das nämlich dem Gradius auch vorzustellen.
Also die Gourmet-Reformen sind zwar ganz okay,
aber vielleicht auch mit dieser Universumsgeschichte.
Du hast irgendwo ein großes schwarzes Loch,
so den Urknall oder sowas.
Und ein Objekt orbitet da irgendwie herum.
Das ist jetzt vielleicht schon mal so eine Galaxie,
und dann, das ist also die
Subklasse, wäre es halt Universum, das wäre
die Basisklasse, von der alles irgendwie erbt,
alles so ein Ding. Das ist ein bisschen groß.
Ja, dann hast du halt eine Galaxie, das ist ja schon
das erste kleine Ding, dann, oh, okay, in der Galaxie
gibt es jetzt ein Sonnensystem. Ein Sonnensystem ist auf jeden Fall
Teil einer Galaxie, da gelten halt die gleichen Gesetze,
physikalischen Gesetze. Und dann hast du ein Sonnensystem, hast du
einen Planeten, das ist jetzt vielleicht schon unsere
speziellere Klasse. Und dann weißt du halt, genau,
das gibt verschiedene Sonnensysteme, die haben vielleicht
gleiche Grundlagen und Planeten,
können jetzt aber verschiedene Dinge
besonders machen. Ja, aber ich glaube,
ich fürchte, also das wird auch,
also mit solchen Dingen,
glaube ich, dass Leute versuchen, da irgendwie so
Alltags-Ontologie irgendwie...
Ja, aber der Orbit ist ja schon,
das passt ja schon, weil dieser Planet, der orbitet
ja, ne, dieser,
diesem Stern, und der Stern, der orbitet
ja dem Zentrum dieser Galaxis, so.
Ja, dann wäre sozusagen die
allgemeinste Oberklasse wäre sowas wie Himmelskörper
oder sowas, oder keine Ahnung.
Nee, nee, nee, ich glaube, das ist gar nicht so,
also Himmelskörper-Objekt, na, ich weiß nicht.
Du brauchst ja schon ein Orbit, das ist ja
Ja, aber ich würde nicht,
ich würde, also das, ich sehe,
ich sehe, dass das immer wieder
passiert und das solche Leute, dass das versucht wird,
das so zu beschreiben und ich finde, das ist
nicht hilfreich, weil, ähm.
Also Mond, Vermieter, Planet.
Ja, das.
Du hast ja irgendwie immer so eine Basisklasse, ja,
und die Basisklasse vom Mond wäre jetzt der Planet, die Basisklasse
vom Planeten wäre das Sonnensystem, die Basisklasse
vom Sonnensystem wäre dann das Universum, die Basisklasse
von dem Universum wäre dann vielleicht irgendwie, ne.
Ja, nee, genau solche Sachen will man eigentlich nicht machen.
Also das ist genau das, was ich, also das ist halt, ja, das klingt so ein bisschen danach, als würde das, aber ich würde das nicht versuchen so auf die Alltagswelt so zu applizieren, sondern es geht tatsächlich darum, dass man Sachen programmieren kann und das ist, das ist oft nicht so wie, das ist halt anders.
Das ist nicht so wie die Welt da draußen, das ist schwer. Oft ist es nicht so, dass man die Welt da draußen modellieren muss und dann das, was man modellieren muss, ist ganz anders als das, was man so draußen normalerweise, man versucht diese Analogien, die gehen immer so ein bisschen ins, ich habe da Schwierigkeiten mit und ich finde, man kann sich das anders besser merken.
Wenn man jetzt, also ich würde sagen, vererben sollte man einfach eher nicht machen, lieber nicht machen. Also es gibt Fälle, wo das richtig und wichtig ist, aber die sind selten. Und was einem aber erklärt wird, ist, dass das der Normalfall ist, so macht man das halt.
Dann würde ich sagen, das ist ganz falsch. Nein, so macht man das eigentlich nicht. Also Vererbung, es gibt Fälle, wo das geht, wo das sinnvoll ist, aber das ist nicht so, dass man das immer machen oder normalerweise so machen sollte, sondern das ist halt eher die Ausnahme. Normalerweise sollte man, wenn man zum Beispiel Code in zwei Klassen wiederverwenden will, dann macht man halt Mixen und nicht diese Vererbung, weil das ist halt, auch am Anfang, das geht ganz gut, sobald es komplizierter wird, hat man da große Probleme, weil deine Hierarchie, die muss halt einfach stimmen, die muss halt passen auf dein Problem.
und das kannst du hinterher nicht mehr gut ändern
und hinterher gut anpassen, das geht alles nicht
so richtig schön und am Anfang zu sehen,
wie das richtig wäre für das Problem, was man
eigentlich lösen will, ist sehr schwer.
Ja, weil man das Problem meistens gar nicht genau weiß.
Genau, man kennt meistens das Problem nicht richtig
und bei Mixins ist es relativ simpel,
das ist halt so wie, keine Ahnung, wenn ich nur,
wenn ich ohne Objektorientierung
programmiere, dann habe ich halt Funktionen,
die ich aufrufe und
wenn ich jetzt merke, ich benutze
den gleichen Code an drei, vier unterschiedlichen Stellen,
ja, dann
mache ich halt eine Funktion
draus und rufe den an den Stellen, wo ich
sozusagen das verwenden möchte,
den Code einfach auf.
Anstelle, dass ich den Code aber nicht stehen habe.
Und genauso kann man das mit Klassen im Grunde auch machen
und Code, den ich in mehreren Klassen benutze,
den ziehe ich halt in Mixins raus.
Und dann ist es relativ easy,
weil
diese Mixins machen halt
nichts anderes, außer irgendwie halt
eine Methode sozusagen hinzuzufügen zu einer Klasse.
ja,
während so Vererbungen,
hm,
das macht halt mehr.
Das tut mehr, also es gibt halt dann diese
Basis, Basis-Klassen, Basis oder so was,
oder es gibt noch so was wie Message,
Resolution-Order, MROs, wo man dann gucken kann,
welche Methoden in welcher Reihenfolge aufrufen
werden, weil die sich ja gegenseitig überschreiben können
und das Problem, was man dann hat, irgendwann ist
das, wenn man da, wie du sagst, einen Fehler macht,
dann hat man
Circle-Vererbung oder so was.
Ja, das passieren halt, genau, wenn man irgendwas falsch macht, dann passieren unerwartete Dinge, die man auch nicht so, die nicht so offensichtlich sind und ja, und es kann auch sehr schnell sehr hässlich werden, also es gibt wenig Fälle, wo das eine super sinnvolle Geschichte ist, das ist immer so, es ist halt so ein bisschen auch wieder wie bei den Dekoratoren, auch wenn man das am Anfang mal verstanden hat, wie das funktioniert, also ich meine, auch wenn man das mit der Vererbung verstanden hat, wie das funktioniert, dann ist das, dann fühlt sich das so toll an, dass man da ganz viele Dekoratoren machen will, ganz viele Vererbungen und am besten das Ganze irgendwie in den
verschachtelte List-Comprehensions-Fakt oder so.
Und mit Abtrag Meta-Klassen bitte?
Ja, Meta-Klassen, oh ja.
Aber
ich weiß nicht, vielleicht keine gute Idee.
Also jedenfalls nicht am Anfang.
Wenn man dann irgendwann genau
weiß, welches Problem man lösen möchte und man möchte
halt ein Framework bauen, das halt, wo man
dann, also nehmen wir irgendwie sowas wie General REST-Framework,
finde ich das relativ gelungen.
Da kann man oft viel
Funktionalität abbilden, dadurch, dass
man jetzt sozusagen von irgendeinem
Viewset oder so erbt und
dann überschreibt man noch zwei, drei Methoden, passt
ein bisschen was an und dann macht das ganz viel.
Sehr schön, aber dafür muss man sehr, sehr genau
verstanden haben, welches Problem man hat und
wenn man
so anfängt, dann
üblicherweise landet man relativ
schnell in einem ziemlich üblen Zustand.
In Teufelsküche, in der Schlangengrube.
Ja, genau.
Man kann das ja immer noch machen am Schluss, wenn man dann
wirklich verstanden hat, was man tut und so, dann kann man ja
immer noch dann irgendwie Klassengereiche hinbauen und so.
Aber am Anfang lieber nicht.
Ich glaube, das ist jetzt der richtige Ort für die nächste Frage.
Die wäre, was heißt ein Monkey-Patch?
Ja, das ist,
da das alles Objekte sind in Python,
kann man die natürlich, und die alle
dynamisch
änderbar sind, kann man ja auch
sozusagen einfach die Methode
eines Objektes einfach,
man kann ja sagen, zum Beispiel, wenn ich
nicht nur Attribute setze, sondern ich kann
auch die Methode einfach überschreiben. Ich könnte zum Beispiel
sagen, wenn ich meinen Barbaren habe, von dem wir eben
geredet haben, und er hat ein Attribut,
das heißt Attacke, und da ist immer irgendwas drauf,
Dann kann ich einfach die überschreiben.
Dann macht er bei der Attacke irgendwas anderes, zum Beispiel heilte ich oder so.
Genau, genau. Und ich könnte einfach sagen,
ja,
baba.attack gleich
lambda xyz, was auch immer
da übergeben wird. Das wäre zum Beispiel
wahrscheinlich die Möglichkeit, wie man
Vererbung bei Klassen
richtig macht, indem man die Basisklasse hat, die wäre
jetzt wahrscheinlich in so einem
Rollenspiel sowas wie eine Person
und dann vererbt man dann auch verschiedene
Rassen,
zum Beispiel Echse oder Mensch oder sowas.
naja, nee, ich wäre da sehr vorsichtig.
Und dann hat man dann Klassen, die man dazu macht,
also zum Beispiel Magier oder Barbar
und dann kann man zum Beispiel Attacke
oder so was schreiben.
Ja, aber das ist halt sehr
verführerisch, dass man halt ein Bild davon hat, wie das
wie sozusagen die Welt, die man
im Spiel bauen will,
aufgebaut ist, aber tatsächlich ist das zu programmieren
oft was anderes, als nur diese Welt zu
modellieren und dann, das ist nicht
das, oder jedenfalls meine Erfahrung ist so, dass
wenn man das so versucht zu modellieren, wie man
sich das vorstellt, dann passt es nicht
so gut auf das, wie man das programmieren will.
Sondern es ist halt einfach,
ja, es ist...
Aber das zu verstehen, das ist vielleicht
schwierig, also für jemand, der das nicht weiß, warum,
wieso, warum man das dann einfach nicht macht, obwohl das
ja so intuitiv endlich so einen Zugang dazu gibt.
Ja, genau, also ich, das ist
halt, es gibt da auch immer diesen
Spruch, es gibt für jedes Problem eine Lösung, die ist
einfach, leicht
zu verstehen, elegant und
falsch.
Das ist halt auch immer, und ich,
was mich ärgert so ein bisschen, ist, dass es halt auch immer so
Programmierlehrbüchern oder so oft so
oder schlimm ist es,
wenn Leute Programmieren
erklären und dann vielleicht gar nicht selber
so da drin stecken, dann machen die
das oft so, dann fangen die da an mit irgendwelchen Analogien
aus dem täglichen Leben zu kommen und dass man
halt so das abbildet, das ist
aber, ich weiß nicht,
da liegt kein Segen drauf.
Das funktioniert
so nicht.
Ja.
Naja. Also ihr seht schon, wenn
Wenn ihr über die Schlangengrube drüber wollt, dann ist da manchmal
so ein bisschen, ja,
Indiana Jones-Seit hängt von der Decke rüber schwingen.
Ich würde, so
Ratschlag wäre halt eher,
versuchen einfach zu halten, nicht so komplizierte Sachen,
so ganz komplizierten Sprachwitscher sind vielleicht nicht so viel
zu verwenden oder
das ein bisschen hinaus zu zögern.
Ja, ich verstehe natürlich, dass das immer so ein bisschen
auch reizvoll ist, aber
nicht irgendwie so, wenn so Dinge
so aussehen, als wie die Weltform, die alles löst.
Sehr skeptisch sein.
Ja, dann machen wir direkt wieder mit einfachen Dingen weiter.
Was sind denn Argumente oder Keyword-Argumente?
Was sind Arcs und Quarks?
Ah, ja, ja, ja.
Das ist auch etwas, was immer ein bisschen verwirrend ist.
Ja, also Funktionen, Methoden haben Argumente.
Das heißt, Dinge, die man übergeben kann.
Ganz normale Positionsargumente sind halt sozusagen das Übliche irgendwie.
Die haben halt eine feste Stelle und werden dadurch dann identifiziert, dass sie halt an der ersten, zweiten, dritten Stelle oder so stehen. Und dann gibt es halt noch Keyword-Argumente, wo man dann explizit dazu sagt, welches Argument man denn jetzt gemeint hat.
Das schreibt man dann halt sowohl in die Funktionsdefinitionen rein, als auch dann, wenn man es übergibt, wobei man es beim Übergeben nicht unbedingt braucht, also da ist es dann halt so, wenn man das weglässt, dann wird halt das nächste Keyword-Argument genommen, das ist so ein bisschen, da können dann komische Sachen passieren und dann ist es auch so, dass man, wenn man jetzt eine Liste von Argumenten übergibt, dann kann man die natürlich alle einzeln übergeben,
man kann die aber auch insgesamt übergeben.
Mit Stähnchen dann bei Argumenten oder
mit Stähnchen, Stähnchen bei Keyword-Argumenten.
Also wenn man die Liste hat in der Hand,
wenn man eine Liste hat oder Tupel, dann kann man einfach
einen Stern davor schreiben und
dann wird das automatisch sozusagen als
ja
Argumente dann übergeben.
Als Impact dann, als Argumenten.
Genau, man sagt dann irgendwie
Funktion, Klammer auf,
Stern und dann eben
Args, Argumente
oder wie auch immer das, die Items,
diese Struktur heißt, die man jetzt gerade in der Hand hat,
Klammer zu und dann kann man in der
Funktionsdefinition drin stehen haben, so was
def Funktion, Klammer auf,
a, b, c und
ja, muss dann natürlich alles irgendwie stimmen von
der Anzahl und so, aber das passiert dann
automatisch. Ich finde bei Keyword-Argumenten relativ
nützlich, weil da kann man alle viele Sachen, die man irgendwie zugewiesen
hat, irgendwie in eine Liste packen
und dann kann man die einfach alles
mit Sternchen, Sternchen übergeben und hat dann seine Keywords.
Genau, das eben
bei normalen Positionsargumenten
ist es halt, entweder man
übergibt sie per Position oder Stern,
kann auch eben in der
Funktionsdefinition sagen, das können jetzt hier
beliebig viele sein, dann schreibt man halt nicht a, b, c
rein, sondern Stern, args,
Komma, und dann
kommen dann halt beliebig viele
Argumente rein, die dann hinterher in der Liste
args sind, wenn man, vielleicht kennen
Leute das noch von Perl oder so, gibt das nur so.
Das geht in Python auch,
ist da aber ein Spezialfall.
Oder, genau,
Und das Ganze geht mit Keyword-Argumenten
ganz genau so, nur dass es dann halt nicht Stern ist, sondern
Stern, Stern. Und damit lassen sich
halt sehr, sehr leicht
zum Beispiel Dicts in
Keyword-Argumente verwandeln und Keyword-Argumente
in Dicts, was
halt manchmal sehr praktisch ist.
Und an viel Schreibarbeit auch Sport.
Cool. Jetzt haben wir noch zwei Sachen, die
noch ein bisschen in diese Funktionen reingehen.
Wir haben ja Funktionen, jetzt jede Menge so Sachen.
Was ist dann Lambda-Funktion? Was macht die denn dann?
Das haben wir, glaube ich, auch schon einmal kurz besprochen.
Das ist eigentlich nichts Besonderes.
Das ist eine Funktion,
wie jede andere. Also was halt in Python
nicht so richtig schick geht.
Ich meine ja auch
ein bisschen JavaScript und das ist da
so schon ein Stückchen eleganter vielleicht.
Oder was es
in Python so nicht gibt, sind so anonyme Blöcke
oder anonyme Funktionen
über mehrere Zeilen oder sowas.
Sondern da gibt es halt Lambda.
Warum muss das überhaupt sein? Wofür braucht man sowas?
es gibt oft irgendwie
Situationen, wo man
eine Funktion übergeben möchte
irgendwo hin,
aber die
sonst nicht braucht.
Also ein Beispiel wäre
jetzt irgendwie, wenn man
irgendwas mit
NumPy
Arrays macht oder so, oder
DataFrames, da
ist es ja so, dass man eigentlich keine Vorschleifen
nicht per Vorschleife über irgendwas
iterieren kann, weil Vorschleifen
super langsam sind im Fallen.
Was jetzt nicht heißen soll.
Vorschleifen sind halt schon gut, aber wenn man jetzt
über ein Array mit ein paar Millionen
Einträgen iteriert, dann will man das vielleicht nicht
als Vorschleife hinschreiben, sondern was man dann
hinschreibt, ist halt irgendwas, dataFrame.apply
und dann übergibt man eine Funktion,
die dann halt
das macht, was man jetzt eigentlich
im Body einer Vorschleife gerne gemacht hätte,
aber die man ja eigentlich hinschreiben kann.
Diese Funktion hat aber sonst keinen Zweck.
Die ist nicht, an anderer Stelle braucht man
die nicht, weil eigentlich, was man hätte hinschreiben wollen,
wäre eine Vorschleife gewesen und dann
das, was man in dieser Vorschleife macht, halt machen.
Aber das geht halt nicht. Daher
ja,
braucht man halt jetzt diese temporäre
Funktion, der man jetzt auch gar nicht unbedingt einen Namen
geben will. Man möchte halt quasi die Quadrate
haben von einer Spalte oder sowas. Irgendwie sowas.
Oder rechnet halt irgendwas aus auf jedem Element
oder so. Und dann, genau.
Lambda
gibt halt sozusagen,
also Lambda x Doppelpunkt
x zum Quadrat
oder sowas, würde halt
ein Argument nehmen und dieses
Argument mit sich selbst multiplizieren und dann wieder
zurückgeben. Nur dass man halt
das Return weglassen
muss. Also Return kann man nicht hinschreiben
in der Lambda, sondern es ist halt
das, was halt man, das Letzte,
was irgendwie...
Implizit wird das halt einfach
zurückgegeben. Und
ja, auch die
Argumentübergabe ist ein bisschen anders.
Es ist halt nicht irgendwie Klammer auf und dann irgendwas,
sondern es ist halt einfach Leerzeichen
und dann Liste der Argumente,
Doppelpunkt und das wird halt
implizit passiert. Und es kann alles
nur in einer Zeile stehen. Es darf nicht
mehrere Zeilen.
Es ist aber so ein bisschen hässlich.
Auf der anderen Seite ist es so, wenn das komplizierter
wird, man muss das ja nicht so machen. Man kann auch
tatsächlich eine Funktion hinschreiben, die man einfach
irgendwie nennt.
Kann man ja auch sagen, irgendwie
rechne mir irgendwie das Quadrat aus
oder so Funktion.
Und dann kann man ja auch mehrere
Zeilen schreiben, die schreibt man dann da rein und dann
übergibt man das Ding halt. Der Lambda-Funktion?
Nicht der Lambda-Funktion, sondern
übergibt das statt der Lambda-Funktion, weil das ist genau
das Gleiche. Das, was man
zurückbekommt von diesem Lambda, ist auch nichts. Das heißt, Lambda braucht man
eigentlich überhaupt nicht.
Man braucht es nicht. Es ist halt manchmal
auch nett, das so hinschreiben
zu können, aber wirklich brauchen tut man es nicht.
Spart ein bisschen Schreibarbeit
für zum Beispiel so einfache Operationen wie einfach Quadrat zu geben,
dann kann man einfach das Lambda in die Zeile schreiben,
wenn man es nicht wieder sonst braucht.
Genau, weil du hast halt, wenn du Funktionen
hinschreibst in Python, immer einen gewissen
Zeilen-Overhead, weil, naja,
da die
Umbrüche syntaktisch relevant
sind und die Eindrückung, ist es halt so, dass
du da auf jeden Fall immer mehrere, mindestens mal
zwei Zeilen für hinschreiben musst.
Ja, und mit Lambda kannst du es auch in
einer Zeile hinschreiben. Und wenn das wirklich eine ganz simple
Geschichte ist, dann willst du vielleicht keine,
nicht deswegen eine Funktion definieren, sondern
ja, aber
letztlich kann man dafür auch ganz normale Funktionen
verwenden und
was ja an Python auch geht, was auch schön ist,
du kannst halt innerhalb von Funktionen auch wieder
Funktionen definieren. Also du musst ja nicht
die Funktionen dann außerhalb der Funktionen. Das heißt, du kannst die Funktion
auch direkt da an die Stelle schreiben, wo
du sie verwenden willst. Wann macht man das denn
alle, dass man so schachtelte Funktionen macht?
Ja, eben. Zum Beispiel, wenn du halt eine Funktion sonst
nirgendwo verwenden möchtest und möchtest
halt, aber du brauchst eine Funktion.
Da sind wir wieder bei, zum Beispiel bei
Clojures, brauchst du das halt,
wo du eine Funktion zurückgibst, die halt
Zugriff auf den Scope
auf Variablen hat, die im Scope
dieser Funktion liegen.
Also wenn du,
also Clojure ist quasi,
du hast eine Funktion und in dieser
Funktion gibst du
jetzt eine andere Funktion zurück.
Eine innere
Funktion sozusagen. Und du möchtest, dass
diese Funktion Zugriff hat
auf eine Variable, die zum Beispiel
innerhalb der äußeren Funktion definiert ist.
Zum Beispiel ein Counter, der mit
irgendwas initialisiert wird. Also genau, das Beispiel
können wir mal nehmen, sagen wir mal
def
zähle
ab, Klammer auf
x, Klammer zu, Doppelpunkt
counter gleich
x und dann def inner
Klammer auf
y
Klammer zu, Doppelpunkt
und dann return
Range
Counter,
Counter,
Y oder so.
Es geht darum, wenn du sagen möchtest,
ab wann etwas zählen soll, dann möchtest
du diesen Counter ja
diesen State wieder halten
irgendwo und du möchtest ihn irgendwo halten, wo
jetzt die innere Funktion, die du zurückgibst, die jetzt dann
irgendwie zum Beispiel irgendwas iteriert oder so,
darauf zugreifen kann. Aber
du willst es sonst nicht
manipulierbar haben. Das ist auch eine, damit kannst
du tatsächlich dann auch
Werte so weg verstecken, dass man
da nicht mehr rankommt. Jedenfalls nicht.
Also man kommt schon, aber dann wird's schwierig.
Nicht mehr so einfach.
Und
ja, dafür braucht man zum Beispiel so
innere Funktionen. Ohne die ginge das gar nicht richtig.
Also, und das nennt man
das ist eine Clojure.
Also, dass sozusagen die innere Funktion
hat Zugriff auf den Counter, den ich irgendwann mal
übergeben hab. Aber
weil die innere Funktion
ja im gleichen Scope ist wie das Ding,
wie das, was ich ursprünglich mal gesetzt habe.
Ansonsten komme ich da von außen aber nicht mehr ran.
Wenn ich jetzt nur die zurückgegebenen Funktionen habe,
dann komme ich an den Counter-Wert nicht mehr ran.
Und dann kann ich halt die äußere Funktion verwenden,
um zu sagen, gib mir einen Counter, der ab 5 zählt immer zurück.
Oder gib mir einen Counter, der ab 10 zählt immer.
Und das 10 oder 5 steht dann halt eben in dieser,
ja, ist ein etwas komplizierteres Konzept, muss man,
aber das ist halt auch die Art, wie dann irgendwie Dekoratoren
und
Context Manager und so
funktionieren. Die machen da
Dinge in der Richtung.
Ja.
Genau. Aber das
finde ich auch sehr schön, dass man
halt in Funktionen auch locker
Funktionen definieren kann. Man kann auch Klassen innerhalb von
Klassen definieren und so. Also das
geht einfach problemlos.
Klingt nach viel Konfusion
für die Anfänger, die jetzt gerade da sind.
Ja, ja, ja. Vielleicht sollte man
Genau, auch wieder, nee, vielleicht sollte man das
mal doch nicht haben.
Ja, ich habe jetzt noch eine
Basisfrage, was ist der Unterschied von einer
Zugweisung von gleich-gleich oder
ist, also nicht zugreifen, sondern
eine Abfrage, was vergleicht man
ein gleich-gleich oder ein ist? Also zum Beispiel
A gleich-gleich, B A ist B, etwas ist
gleich-gleich, non, ist non.
Ja,
also
wenn
ich gleich-gleich verwendere,
also gleich ist natürlich irgendwie
Zuweisungen, aber gleich, gleich,
da wird halt der Wert verglichen.
Also
und bei is wird
verglichen, ob es das gleiche Objekt
ist. Und deswegen
bei none sagt man immer is none, weil
es nur ein none-Objekt gibt. Genau, none
ist ein Singleton.
Und deswegen kann ich halt so testen,
ob es wirklich none ist.
True und false sind auch Singleton.
ja
bin ich mir jetzt nicht so ganz sicher, aber
ich glaube schon
ich weiß aber nicht
ja, so müsste wahrscheinlich so sein, das könnte eigentlich
gar nicht anders
okay, das heißt, er müsste halt tatsächlich, wenn er ist,
genau das Objekt
ich weiß nicht, man kann das
aber man kann das auch zuweisen, also es ist auch ganz böse
man kann True und False auch noch anders
belegen, also
müsste man mal nachgucken, ich weiß nicht genau
was irgendwie spannend ist, weil jetzt, wir haben ja so ein paar
mal über so Sachen geredet, was jetzt irgendwie Klassen sind
und Objekte und Typen, dass alle Sachen in Python
irgendwelche Objekte sind, irgendwelche Typen sind.
Und dann habe ich mich irgendwie gefragt, ob
jetzt nicht die ganzen Zuweisungen, also man kann
jetzt irgendwie Typen umwandeln, ja, also von Integer
auf String oder sowas, ob das nicht halt auch
eine Klasse
dann eigentlich ist, die man dann halt nimmt, weil das halt
ein Typ ist, ein Objekt ist, deswegen müsste das eigentlich
großgeschrieben werden, weil man halt eine Instanz
eines Objektes ändert und eine Instanz eines Objektes erzeugt.
Zum Beispiel von einer Instanz eines Objektes
String, eine Instanz, also wenn man das Integer wechselt,
wenn man ein Inter vorstellt, es muss ein bisschen großes Int sein,
dann an der Stelle irgendwie
war ich dann ein bisschen verwirrt.
Ja, also ich rate jetzt mal,
woher das kommt. Ich weiß es ehrlich gesagt auch nicht so genau.
Vielleicht weiß das jemand besser und kann mich da korrigieren,
aber ich denke mal, es liegt daran,
dass das Build-Ins sind.
Also ja, eigentlich die Konvention in Python
ist so, wenn es eine Klasse ist, dann schreibt man das halt
groß, aber
ich glaube,
alle Build-Ins sind klein.
Und da das Build-Ins sind, sagt man eher, das ist wichtiger, weil es gibt nicht so viele Build-Ins.
Aber richtig wäre es tatsächlich, dass man, zum Verständnis vielleicht, dass man irgendwie, wenn man einen Typ ändert, einer Variable beispielsweise, dass man einen neuen Instanz, eine neue oder eine andere Klasse erzeugt.
Ja, ja, das ist so, aber das passiert auch tatsächlich.
Also wenn ich sage int, Klammer auf, 5, Klammer zu,
dann wird ein neues Integer-Objekt erzeugt, genau, mit dem Wort 5.
Also es ist tatsächlich, ja, auch Dict ist ja eine Klasse tatsächlich.
Ich kann ja auch davon erben und so, sollte ich vielleicht nicht machen,
aber ich kann davon erben und das funktioniert auch.
Aber ja, ich denke, das hängt damit zusammen,
dass die Build-Insights so Spezialfälle sind.
Wenn ich die Klassen verwenden möchte,
für die ganzen Dinger gibt es auch noch richtige Klassen.
Zum Beispiel für Dikt und List und so
gibt es UserDikt und UserList.
Und auch wenn ich jetzt irgendwie selber ein eigenes Dikt,
das Dinge ein bisschen anders macht als ein normales Dikt,
verwenden möchte,
dann sollte ich halt irgendwie von UserDikt erben
und nicht von einfach nur kleingeschriebenem Dikt.
Dass die das nie, weil sich schon Leute
darum gekümmert haben, bestimmte Probleme zu umgehen, auf die man
dann stößt, wenn man das nicht macht.
Ja, genau.
Ja, jetzt haben wir
noch jede Menge, ich weiß gar nicht, ob wir das heute
in der Folge alles irgendwie unterkriegen.
Noch einer hat gefragt, was denn eine Shallow Copy ist.
Achso.
Wie arbeitet man richtig mit Listen im Zusammenhang
mit Funktionen? Gibt man eine Kopie und
retürnt eine neue Liste oder gibt man eine Liste und
ändert die quasi in Plays?
Was hat das damit zu tun?
Also irgendwie.
Ja, das ist auch eine unter Umständen Stilfrage, was man da machen möchte.
Also einmal, vielleicht zuerst das mit der Shallow-Kopie.
Also die Frage ist, was passiert eigentlich, wenn ich jetzt sozusagen eine Kopie von irgendwas machen möchte,
und weil ich warum auch immer irgendwie eine zweite Version von irgendeiner Datenstruktur brauche oder so,
Da ist es, wenn ich jetzt die einfach nur kopiere,
also in Python habe ich eigentlich immer Referenzen
auf solche Datenstrukturen in der Hand.
Also auch die Übergabe von Sachen ist immer bei Referenz.
Also es gibt ja ein C, es ist unter Umständen anders.
Da kann ich Argumente übergeben als Referenz
oder halt als Wert, also direkt den Wert einfach so.
Und in Python ist es immer per Referenz.
Also in der Variable, die ich übergebe, steht immer sozusagen einfach eine Speicheradresse drin, die halt auf das Objekt zeigt, das ich übergebe.
Und ich übergebe immer nur die Adresse, ich übergebe nicht der Funktion das Objekt selbst.
Und jetzt ist es halt so, wenn ich einfach nur, bestimmte Operationen duplizieren mir halt jetzt diese Adresse, aber nicht den Inhalt dahinter.
Das heißt, wenn ich jetzt, ich mache eine Kopie davon, ich muss mal überlegen, in welchen Umständen ich das hinkriege.
Wenn ich jetzt einfach nur kopiere, dann kann es sein, dass mir nur die Referenz kopiert wird. Das heißt, mir wird halt die Speicheradresse in eine andere Variable kopiert, aber wenn ich jetzt irgendwas am Inhalt einer Liste oder so ändere, dann ist das in beiden Listen geändert.
Und das ist unter Umständen nicht so intuitiv. Vielleicht hätte man jetzt nicht so mit gerechnet, sondern man hätte damit gerechnet, dass ich jetzt zwei Listen habe, die im Hauptspeicher an zwei unterschiedlichen Stellen liegen.
Und eine Shallow-Kopie ist halt eine, die nur sozusagen, also bei einer Liste könnte ich mir jetzt sogar vorstellen, dass es oft, wenn ich jetzt nochmal eine Liste drumherum schreibe oder so, dass dann tatsächlich eine Kopie erzeugt wird, also eine Nicht-Shallow-Kopie, aber wenn ich jetzt eine komplizierte Datenstruktur habe in irgendeinem Dikt oder so, wo viele Sachen ineinander verschachtelt drin liegen, dann ist es so, wenn ich jetzt sage Dikt von dem Ding, dann ist es eine, oder wenn ich sage Kopie, dann ist das eine Shallow-Kopie.
Warum brauche ich dann überhaupt
eine Schellokopie? Dann könnte ich auch einfach auf das normale Dikt zeigen,
wenn es eh nur auf das gleiche Objekt zeigt.
Das ist eigentlich nur eine andere Benennung.
Wenn ich die Inhalte mit kopieren will,
dann gibt es
zum Beispiel
eine Funktion aus dem Copy,
ich glaube, das ist Standardbibliothek,
dann sagt man immer FormCopy, ImportDeepCopy
und dann sagt man DeepCopy, irgendwie
komplizierte, dick verschachtelte Datenstruktur
und die geht dann rekursiv
da durch und kopiert den ganzen Kram da raus
in eine andere Datenstruktur. Und dann habe ich halt
das tatsächlich getrennt voneinander. Aber
ansonsten ist das halt nicht so einfach.
Wenn ich da
Dict drumherum mache, dann kann es
zwar auch sein, dass es ein neues Dict ist an einer anderen
Speicheradresse und dass ich
die Keys und Values kopiert habe, aber
die Values waren halt Referenzen auf irgendwas
und die Objekte hinter diesen Referenzen haben sich
halt nicht geändert. Und das kann halt sehr...
Da kann man sich so ein bisschen mit am Fuß schießen, wenn man so was
übergibt wie leere Listen als Standardwert vom
Keyword. Ja, da kann man sich
böse in den Fuß schießen mit. Weil dann, also das ist glaube ich
generell das Problem, also bei so
ein paar Sachen, die man als Keyword setzt, ja, wenn man
irgendwie eine Funktion hat, da wird ein Keyword
übergeben, das setzt man einem Default-Wert,
indem es zum Beispiel eine leere Liste hat oder einen
random initialisierten Wert oder sowas,
der wird halt beim ersten Mal dann
initialisiert und da steht dann halt aber in der Speicheradresse
dieser Wert drin, der dann halt dem zugewiesen ist schon,
weil das halt dann nur darauf zeigt und halt nicht
jedes Mal ein neues Objekt generiert und das
heißt, man hat immer dieselbe leere Liste,
die dann vielleicht nicht mehr leer ist, nachdem man die Funktion
einmal aufgerufen hat und dann...
Und dann ist es immer die gleiche und dann funktioniert es sogar oft
und dann irgendwann fällt es einem ganz
furchtbar auf den Fuß und man weiß nicht genau,
an solchen Problemen habe ich auch schon lange
rumgedebugt, bis ich mir dann so, oh nein,
das ist immer die gleiche Liste, oh scheiße.
Und da ist auch da
eine Konvention, dass man das eben eigentlich,
dass man nicht als Default-Argument
in eine Funktion reinschreibt,
irgendwie
Default gleich
Klammer auf, Klammer zu oder so.
Man sagt immer None und dann macht man eine Überprüfung,
Und dann ersetzt man die Liste neu.
Das ist halt echt nur eine böse Fußange.
Das kann einen schwer erwischen.
Ja, bei Random-Werten übrigens genau dasselbe.
Also wenn ihr jetzt irgendwo so ein Zufallswert generieren lassen wollt,
wie von Random-Rant 1 bis 10 oder sowas,
und dann habt ihr ihn einmal initialisiert,
der gibt nicht jedes Mal, wenn ihr die Funktion aufruft,
einen default neuen Zufallswert zurück,
sondern immer dasselbe.
Also das ist an der Stelle nicht intuitiv.
Also fand ich auch sehr komisch,
dass er dann nicht einfach jedes Mal beim Aufrufen das neu initialisiert,
sondern dass er halt dann die Objekte nimmt,
die er einmal schon irgendwo liegen hat.
Ja, also eine Geschichte, also List Comprehension macht immer eine Kopie, wenn man zum Beispiel eine neue Liste erzeugt, ansonsten die Kopie aus dem Kopiemodul, wenn es kompliziertere Datenstrukturen sind, dann muss man sich das nicht selber, ich meine, es ist ja wirklich kompliziert, man muss halt rekursiv durchgehen und das will man ja vielleicht auch nicht selber schreiben und da gibt es halt schon ein Ding für, was man da benutzen kann.
Dann ist es so, naja, was diese unterschiedlichen Stile angeht, also wenn man sich so ein bisschen anguckt, es gibt ja unterschiedliche Arten zu programmieren, so Imperativ, ich würde auch Python eher, auch wenn man es auch mit Berechtigung sagen kann, ist es auch irgendwie eine funktionale Programmiersprache, ist es doch eher, die meisten Leute verwenden es halt irgendwie Imperativ.
Und in dem Lager sozusagen Paradigma der funktionalen Programmiersprachen ist es aber eher so, dass man halt da und nicht nur da, das setzt sich auch in anderen Bereichen durch. In JavaScript sehen wir das in letzter Zeit oft, auch wenn es um so State-Handling-Geschichten geht.
Da gibt es dann Redux und so, dass man, wenn man jetzt solche Sachen handelt, versucht immer nur mit Datenstrukturen zu arbeiten, die nicht veränderbar sind, also die mutable sind und immer nur Kopien erzeugt, wenn man irgendwas ändert.
Also man ändert nichts in einer bestimmten Datenstruktur, sondern man erzeugt eine neue Kopie und an der ändert man dann halt irgendwas, beziehungsweise man ändert nichts, sondern man baut es dann halt neu.
Was halt diverse, sehr, sehr
coole Nebeneffekte hat. Unter anderem,
dass ich Sachen dann perfekt parallelisieren kann,
dass ich
weiß, dass ich keine Seiteneffekte habe,
dass ich super testen kann.
Es hat eine Menge
und immer wenn Leute, die aus so einer
funktionalen Ecke kommen, sehen, was man so
in Python imperativ macht, dass man irgendwie
Attribute von irgendwelchen Objekten ändert oder halt
irgendwie ein Dicte übergeben bekommt,
das dann irgendwie ein Ende hat
und dann
würde man jetzt in funktionaler
richtigen
Funktionalen Programmiersprache
würde man nie irgendwie
einen Dikt oder eine Liste oder sowas in der
Funktion nehmen, da irgendwas dran ändern und
das Ding dann wieder zurückgeben oder so, oder am besten
gar nicht zurückgeben, sondern einfach nur ändern.
Sondern man würde immer, wenn man was
ändert, eine neue Kopie zurückgeben.
Weil man dann halt diesen ganzen schönen
Effekt hat, was, wenn man das nicht
tut, was, würde ich sagen, aber
in Python oft so ist,
also man übergibt irgendwo
eine Liste und dann ändert man irgendwie ein Element
in dieser Liste und dann gibt man die Liste wieder zurück,
dann gehen ganz viele
schöne Sachen nicht mehr, weil dann ist es halt
ja.
Man hat vielleicht irgendwas kaputt gemacht.
Ja.
Was auf der anderen Seite manchmal halt auch total
viel einfacher macht, als wenn man
es funktional schreibt und auch
effizienter, weil einmal ist es so,
man kann halt Dinge nicht mehr so richtig direkt beeinflussen
und es ist halt so,
wenn man alles immer kopiert und jetzt
man aber jetzt große Datenmengen hat,
zum Beispiel im Data-Science-Bereich ist es halt, wenn
deine Datenstrukturen alle hunderte Megabyte groß sind
und du machst immer Kopien von allem,
was auch, also tatsächlich, Pandas
macht das auch per Default, wenn
alle Operationen gehen, immer Kopien zurück.
Aber das kann auch ganz schön
in den Hauptspeicher gehen. Manchmal muss man dann schon
sagen, so, ja, hier bitte nicht kopieren, das geht einfach
nicht, passt dann nicht mehr. Und dann
muss man halt
Sachen direkt
in place ändern oder so und das ist natürlich
immer ein bisschen schmutzig, aber ja.
Weekend 30, ja, ja.
Dunkle Magie, wieder.
Ja, also hängt davon ab, würde ich sagen,
was man für ein Problem hat und
also wenn man das nicht kennt, dann sich mal so
anzugucken, wie man mit alten Datenstrukturen
einfach nur Immutable irgendwie hält
und immer kopieren soll, das ist eigentlich schon
sehr schick, aber...
Dann schließ direkt an, was ist denn deine Lieblingsdatenstruktur?
Meine Lieblingsdatenstruktur?
Also ich tatsächlich, ja,
Dict.
Hätte ich jetzt auch gesagt, früher fand ich Listen ganz toll Dict,
aber ich auch.
Vielleicht ein bisschen, wo man gerade ist, ja.
Und vor allen Dingen ist die Dict-Inflamentation
in Python ist halt auch total super.
Also die ist richtig schnell.
Die ist halt
ein sehr effizientes Ding und
ein Riesenhaufen Probleme lassen sich dadurch schon lösen.
Also wenn man das ordentlich verwendet,
dann kriegt man da so einen sehr
großen Teil der so 0815
Programmiergeschichten, die man so macht, kriegt man halt mit
Listen und Dicts irgendwie abgebildet.
Listen braucht man auch,
halt gerade, wenn man irgendwelche Dinge
iteriert und so, aber Dicts ist
halt das Schöne daran ist, dass man halt irgendwie
sozusagen beliebige Dinge irgendwie speichern
kann und man kann die
Namen,
unter denen man das findet, dann halt irgendwie dynamisch
generieren und muss das halt nicht vorher definiert
haben in Code.
Und
wann nutzt man denn Tuple, das Datentruktur, wenn man eine Liste
hat? Also warum ist das überhaupt? Ja, Tuple
sind halt
immutable, ja genau. Das ist
halt der Grund, deswegen
an den Stellen, wo man es halt immutable
haben will, dann kann man die halt gut nehmen.
unter anderem zum Beispiel, wenn du halt
möchtest, dass etwas key in einem Dikt
sein kann. Das geht halt mit einer Liste nicht.
Da musst du halt einen Tuppel nehmen.
Oder halt bei so Geschichten
wie Tuppel, Unpacking und so,
das geht auch nur mit...
Unpacking geht auch mit Listen, ja.
Klar, das geht auch mit Listen, aber ich weiß, ich überlege jetzt gerade,
ob es einen tieferen Grund gibt, warum
Argumente ein Tuppel sind.
Also, ja.
generell. Also Dickey war vielleicht
eine gute Idee, ja.
Es gibt schon den
Fall öfter mal, dass man das halt nicht
änderbar haben will und dann nimmt man halt ein Doppel
statt eine Liste. Aber tatsächlich
ist es so, es gibt auch
Skalare, sozusagen einfache Werte
irgendwie, also sowas wie eine 5 oder
String, wobei
Listen und Dics ist halt auch so das, was man
in allen Programmiersprachen irgendwie oder
vor allen Dingen in allen Skriptsprachen irgendwie eingebaut
findet, ja, das hast du halt auch in Perl und in PHP
und in JavaScript, die
heißen halt in allen diesen
Programmiersprachen irgendwie ein bisschen anders, ne, in Perl
heißt es halt Hash und
Array, ja, in PHP heißt es
Assoziatives
Array
und in, weiß ich nicht,
JavaScript heißt es halt Object
und
ich glaube, da heißt es aber dann auch Array, ja.
Naja, aber
diese Grunddatentypen hast du halt
überall, deswegen war das halt,
Damit kannst du halt schon eine Menge machen.
Und Tupple gibt es halt eigentlich, glaube ich, nur in Python
und anderswo nicht, weil es auch
sonst nicht so häufig verwendet wird.
Ist halt schon eher so ein bisschen
Spezialfall.
Ja, es gibt auch
oft von den ganzen
also was auch mittlerweile, glaube ich,
ein integrierter Datentyp ist, ist halt
Set in Python.
Das ist auch eine Datenstruktur, die wir
relativ häufig, oder ich benutze sie relativ häufig
und von denen gibt es halt dann auch
Immutable-Varianten. Ich weiß jetzt gar nicht, ob es
Immutable-Tickets gibt,
aber zum Beispiel von Sets gibt es halt Frozen-Set,
eben auch für solche Fälle, wie du möchtest,
dass es irgendwie als Key in ein Ticket ist
oder so. Und
den kannst du halt dann nicht mehr verändern.
Vielleicht gibt es auch sowas wie eine Frozen-List,
ich weiß nicht genau.
Aber Frozen-Set benutze ich tatsächlich
ab und zu. Frozen-List ist Tupel?
Ja, könnte sein, genau. Frozen-List ist Tupel, ja, genau.
Ja, ja.
Okay.
Wann nutzt man denn Manant Nampai Erase?
Ja, immer dann, wenn man halt
sozusagen
so viele Daten hat, dass es
irgendwie nervtötend wird ansonsten.
Und
wenn man jetzt die ganzen Spezialfunktionen vielleicht
verwenden will, die halt auch in NumPy und so mit
drin sind.
Ja, und genau, dann gehen
halt die Sachen, die sonst lange dauern, halt
einfach schnell und
muss halt ein bisschen anders programmieren.
Es ist halt dann alles drauf ausgelegt, dass das
vektorisiert wird und
das heißt, Vorschleifen und sowas gehen eigentlich
nicht mehr. Und was natürlich ein bisschen sehr anders
ist als das, was man normalerweise macht.
Aber, ja.
Okay, dafür braucht man dann bei NumPy Arrays
muss man dann mit Lambda's arbeiten oder
Ja, oder halt die Funktionen verwenden, die es
schon gibt. Das meiste gibt es ja, sozusagen
würde ich mal sagen. Und dann ansonsten, wenn es das halt nicht gibt,
dann genau, übergibt man halt eine Funktion.
Okay.
Wie sehr realisierst du denn dann Daten für
Übertragungen?
Ja.
Kommt drauf an.
Also erstmal, was das überhaupt zu realisieren ist,
ist halt in eine Zeichenkette umwandeln,
dass man das irgendwo hinschicken kann und dass
wenn man dann weiß, was dahinter steckt, dann man daraus wieder Objekte
baut, mit denen man Dinge tut.
Ja, oder genau, ich würde sagen, man hat
eine Datenstruktur und man möchte sie halt in irgendeine
Form so verwandeln,
dass man sie halt irgendwie über Netzwerke schicken kann
oder irgendwo hinspeichern kann und man
lädt sie hinterher irgendwo wieder.
Oder kann auf Papier, dann kann man sie abschreiben.
Und hat die gleiche Datenstruktur
wieder irgendwie.
Und das kann man natürlich, je nachdem
wie kompliziert das ist, was man halt da
ein- und
auspacken möchte, beliebig kompliziert gestalten.
Also das, was heutzutage ganz
oft verwendet wird und insofern ist es auch
keine so schlechte Wahl. JSON wird
halt oft benutzt.
Du kannst halt einfach
nach JSON verwandeln.
Alles, was irgendwie so Richtung Dikt ist oder verschachtelt
Dikts. Also meistens
hast du irgendwie Listen und Dikts
irgendwie ineinander verschachtelt sozusagen als Datensstruktur.
Das kannst du halt hervorragend irgendwie als JSON
einfach realisieren. Also auch mit Frequenzmentation
kein Problem, auch mit Tucheln kein Problem.
Daten, also
Datums. Genau, das ist
Datumsformate. Das ist halt
halt blöd. Genau, solche Sachen gehen dann schon nicht mehr
so gut. Also wenn du jetzt
ein Datum hast, dass du irgendwie oder
einen Zeitpunkt, wenn du den
irgendwie in JSON
speichern willst, dann ist es halt blöd.
Also der Flur von Datum ist Daten. Das ist aber gerade
ein bisschen verwirrend, wenn wir über Daten schon so reden.
Aber ja. Ja, genau.
Das ist ein bisschen kacke.
Und dann gibt es natürlich dann
diverse ISO-Standards, wie man das dann doch
irgendwie mit Zeitzone und keine Ahnung
und dann bist du aber darauf angewiesen, dass alle irgendwie
die gleiche Idee davon haben, was denn jetzt in diesem
String, der da in dem JSON
steht, was das
jetzt gemeint ist. Und das ist manchmal ein bisschen
nervtötend.
Aber
solange man nicht, also Datum ist immer etwas, was
meistens dann Probleme macht, aber einfach
so Listen,
Dicts, Strings,
das funktioniert ganz gut.
Und ja, also für diese
einfachen Fälle ist JSON
ganz gut geeignet.
Da da auch mittlerweile so viel verwendet wird, ist da auch viel Arbeit
reingeflossen, die Parser und
Rausschreibdinger
halt schnell zu machen und das geht eigentlich
alles ziemlich gut.
Es ist halt auch halbwegs sparsam,
was halt sozusagen den Platz angeht.
Wenn du jetzt eben sowas wie XML nimmst,
XML ist halt da, kannst du mehr mitmachen,
aber es ist halt komplizierter,
viele Dinge sind da schon gedacht worden,
aber das ist halt einfach,
es wird oft riesig.
Was heißt mehr kann man damit machen?
Warum? Ja, da kannst du halt,
du kannst da ja ein Format dann definieren,
Du kannst ja halt irgendwie auch
definieren, wie die Daten aussehen.
Du kannst beschreiben, wie das, was du
reinschreibst, wann das
okay ist. Du kannst halt eine DTD
Data, wie heißt das?
Data Type Definition zu deinem
XML dazuschreiben, das halt sozusagen
definiert, wie das Format von deinem
XML aussieht. Und dann kannst du das validieren
dagegen und so.
Ja.
Ein heimlicher
XML-Fan? Nein.
Nein, das ist alles sehr
schrecklich. Also ich meine, man kann
das machen, aber das ist alles...
Nee, es gibt auch einen Grund, warum das quasi
niemand... also niemand
tut.
Das ist...
Ja, also
in der Anfangszeit war das...
Also mittlerweile ist das auch alles nicht mehr so
schlimm. Es gibt gute Bibliotheken, aber
es war schon nicht so einfach
manchmal. Und was halt an XML nervtötend
ist es halt, du kannst es als Mensch nicht gut lesen,
es ist halt gigantisch groß.
Hässlich. Hässlich,
ja.
Ja, und
dann gibt es natürlich noch sowas wie Jammel oder so,
heute irgendwie so ein bisschen auch wieder
en vogue. Auch hässlich.
Ist aber auch, ja, ist auch ein bisschen hässlich,
muss man leider sagen, ja.
Wie hat das dann jemand
formuliert, ne, so irgendwie Jammel,
das, was dabei rauskommt,
wenn man irgendwie alle Fehler ignoriert,
die bei JSON gemacht worden sind.
Und JSON ist das, was rauskommt,
wenn alle viele kreative XML gemacht worden sind.
Und die Geschichte wiederholt sich immer und immer wieder.
Irgendwie das nächste Format heißt,
was man nicht gebrauchen kann.
Genau, das ist halt echt so ein,
aber XML ist auch so ein bisschen,
das wurde früher immer gespottet,
dass man dem Format ansieht,
dass es irgendwie von Juristen
und nicht von Informatikern konzipiert wurde.
Und dass man irgendwie solche Sachen nicht hat,
wie, also, du kannst es nicht ordentlich quoten.
Wenn du jetzt zum Beispiel,
innerhalb von XML gibt es halt so was
wie Kommentare. Wie willst du XML-Kommentare
quoten? Das geht überhaupt gar nicht.
Und das heißt, wenn du jetzt zum Beispiel
in einem XML-Dokument
beschreiben willst, wie denn jetzt XML auszusehen
hat mit XML-Kommentaren,
da passieren ganz schreckliche Sachen. Das geht alles überhaupt
gar nicht. Und das ist halt so.
Es kann auch nicht sein, dass daran keiner gedacht hat,
dass das jetzt nicht geht. Das geht einfach nicht.
Und ja, es ist nicht so,
dass man sich sagt, das ist voll super elegant,
total gut, nehmen wir jetzt sofort.
Sondern es ist mehr so, oh,
oh, schrecklich.
Und JSON ist aus dieser Perspektive
für mich weniger schrecklich. Also es ist halt,
es kann deutlich weniger, aber
okay, dafür ist es halt alles
nicht so schlimm. Ist ja zum Serialisieren da, also dass man
Daten irgendwo hinlegt als Pfeil
oder sowas. Aber es gibt natürlich dann gewisse
Begrenzungen, was halt dann nicht gut
funktioniert. Eben, ja, Datum oder
alles, was irgendwie komplizierte Objekte sind und Code
kannst du da auch nicht mit reinpacken.
Das geht alles nicht.
Und auch dann für die Übertragung
im Netz ist halt auch teilweise nicht so gut,
weil das halt dann Text ist und
das hat also bestimmte schlechte Eigenschaften.
Du möchtest eigentlich,
naja, da gibt es dann sowas, da gibt es dann ein etwas
besseres Format, Message Pack nennt sich das,
das kann man halt, das ist so ähnlich wie JSON, bloß
binär so,
dass das halt irgendwie
nicht kaputt gehen kann bei der Übertragung
oder nicht so leicht kaputt gehen kann wie JSON.
Ja,
und, naja,
aber JSON ist eigentlich schon, würde ich sagen,
für viele Fälle so das, was man eigentlich
haben will. Und
wenn es dann noch viel komplizierter wird, kann man auch
sowas nehmen wie Pickle, da muss man aufpassen.
Ja, es gibt noch
in Python selber,
wenn ich jetzt überlege, gibt es noch eingebaute
Geschichten. Es gibt noch Marshall, das Modul, das macht sowas
ähnliches wie JSON,
bloß halt binär. Das ist auch noch ein Stückchen
schneller. Und dann gibt es noch
Shelf, glaube ich. Das weiß ich aber nicht.
Das habe ich schon ganz lange nicht mehr verwendet.
Und eben, wenn man jetzt
aber nicht nur Daten
serialisieren will, sondern vielleicht
auch Code mit, also komplette Objekte
mit Funktionalität,
dann sowas wie Pickle.
Und Pickle kann man auch schicken als Binär-File,
dann über das Netz. Genau, man kann
verwandelt halt ein komplettes Objekt
zum Beispiel in einen binären String
und dann schickt man den irgendwie über das Netz.
Auf der anderen Seite deserialisiert man den
und dann hat man dieses Objekt wieder da.
Das ist natürlich sehr praktisch.
Was ein bisschen schlecht dran ist, ist, man muss halt sehr aufpassen,
dass man dann führt der Code aus.
Also wenn
einem jemand irgendwie, der nicht
vertrauenswürdig ist,
irgendwas Gepickeltes schickt,
da kann ein beliebiger Code drin sein.
Also wenn man das anpickelt,
dann führt man das aus, was da drin steht.
Das heißt,
das sollte man sich klar machen.
Hier ist eine Bombe.
Genau.
Also irgendwas
anpickeln, was einem jemand
gibt, ist so wie Code ausführen,
wenn es jemand gibt.
Wenn ich ein Paket öffne, was man nach Hause geschickt bekommen hat,
da kann auch eine Briefbombe drin sein.
Das ist immer auch beim Essen,
Wenn man isst, was man nicht kennt, dann immer Vorkost
da daneben.
Ja.
Man weiß nicht so genau.
Die Paranoia kann ja beliebig weit getrieben werden.
Genau, genau, genau.
Pickel, lass mal überlegen. Es gibt da noch
diverse, es gibt da noch für den
wissenschaftlichen Bereich ein paar Sachen. Es gibt noch
HDF 5,
Net, wie heißt das Ding, Net CD.
Ich hab's
jetzt wieder vergessen.
Wie der Standard ist.
Es gibt so eben für wissenschaftliche
Daten, da gibt es noch Standards,
wie man Sachen speichert,
die noch so ein bisschen anders sind.
Eine CDF, glaube ich,
ist das. Ja, so ein HDF5
ist einer der, das gehört
da irgendwie mit rein in diese Reihenfolge.
Ja, hört sich irgendwie total kaputt an.
Ja, und
NumPy-Arrays haben auch noch mal eine eigene
Möglichkeit, wie man sie serialisieren kann.
Man kann die auch Memory mappen.
Ja, oder ich meine, CSV ist auch eine Möglichkeit,
Sachen zu serialisieren. CSV ist auch wieder so ein Format,
so eigene, fürchterliche,
schreckliche Sachen mit sich bringt.
Aber
also in anderer Sicht
ist es auch wieder ganz gut. Also oft
würde ich sagen, wenn man
die Wahl hat zwischen CSV und XML, ist CSV
die bessere Wahl.
Aber ja.
Tja.
Ja, aber das
war es im Grunde eigentlich. Haben wir noch
eine wichtige Serialisierungsgeschichte?
Ja, ich glaube, wir wollen ja auch, eigentlich wollen wir ja nur eine Minute
reden. Ich glaube, das halten wir jetzt.
Ui, ui, ui, ui.
Ja, ich habe jetzt noch so ein paar Themen, die sind irgendwie jetzt alle aber sehr unzusammenhängend
auch. Ich überlege gerade,
wo ich damit jetzt noch anfangen soll. Ich glaube,
Memory Management hatten wir schon mal gesprochen. Ich glaube, in einer der ersten
Folgen haben wir ja über den JIT und den GIL gesprochen.
An den Just-in-Time-Compiler
und an den Global Interpreter-Log.
Dann habe ich
jetzt noch das Konzept von MapReduce, aber ich weiß
nicht, ob das jetzt hier zugehört, dass das irgendwie
nicht ganz da reinpasst. Nee, ich glaube, es ist auch so ein bisschen veraltet.
Also inzwischen macht das keiner mehr.
Und dann, was mich aber natürlich noch
interessiert, wenn man halt debuggen möchte, was da irgendwie
der Zeug ist, dann gibt es irgendwie so ein bisschen
so, ich nenne es jetzt mal Deep Debugging.
Das heißt, man kann Deer auf irgendwelche
Fehler spawnen oder Help aufrufen
und so. Was gibt es denn da noch? Und wie würde man
sich dann angucken, was überhaupt möglich ist
mit so Objekten, die man da zurückbekommt,
wo man nicht genau weiß, woran liegt denn das jetzt?
Guckt man denn da genauer rein?
Naja, ich glaube, das ist schon, also Help zeigt halt den
Also macht man Help, das ist eine Funktion,
die man außen rum schmeißt und was, was zurückkommt?
Ja, aber das
also an den Objekten hängen halt
auch immer Dinge dran, also zum Beispiel man an den
Funktionsobjekt hängt da halt auch mal die Dokumentation,
also der Dockstring hängt da halt mit dran, den man sich dann
angucken kann. Und ich weiß nicht genau, was Help macht, aber
Help, glaube ich, wird sowas tun, wie
die Dockstrings nehmen und anzeigen,
mehr oder weniger.
Und dir zeigt
halt alle Attribute und Methoden
oder so an einem Objekt,
die da so dranhängen.
Und dann, ja,
also zumindest kann man sich dann,
zeigt es auch die Funktion Signature, glaube ich, an
noch. Was gibt es denn noch?
Nee, mehr verwende ich eigentlich auch
praktisch nicht.
Dieses MRO, dieses Basis,
also wenn man so eine von diesen Objekten, die man mit dir
dann rausbekommt, sich anguckt, dann
bekommt man natürlich noch viel mehr Informationen, weil diese ganzen
Magic Methods, so Meta-Attribute
irgendwie von den Klassen dranhängen, dass man
zum Beispiel jetzt mit Basis sehen kann,
welche Oberklassen hat denn überhaupt
das Ding, wo ich dann drin bin. Ah, okay, cool.
Nee, hab ich noch nie verwendet, glaube ich.
So kann man halt noch ein bisschen tiefer reingucken in dieses
Vererbungshierarchie-Ding und dieses
MRO, also diese Method Resolution Order, zeigt dann
dann vielleicht genau, welches von den
Dingen aufgerufen worden ist,
von den Methoden, die man jetzt in reiner
Weise überschrieben hat und was da eigentlich hintersteckt,
damit man vielleicht weiß, oh, es wurde etwas Falsches
aufgerufen. Also so kann man so ein bisschen immer gucken,
wenn irgendwas schief geht, wo man überhaupt nicht weiß, was man
da gemacht hat, dass man nicht mehr irgendeinen Komma vergessen hat,
wie man dann da reinkommt.
Wobei da dann vielleicht auch
eine bessere Wahl wäre, einfach direkt
einen T-Bugger zu verwenden.
Ja, welchen würdest du da empfehlen?
Ja, PDB ist halt so das, was
und man kann ja auch inzwischen...
was macht PDB? Also der stoppt den Code
zur Ausführzeiten, man hat eine Shell und kann dann
da hochgehen.
Du kannst halt auch irgendwie, genau,
im Code halt rein
Set Trace,
da muss ich mal nachgucken,
schreibst halt einfach deinen Code rein
und dann hast du da halt
ein, stoppt halt
die Ausführungen an der Stelle
und du kriegst halt ein interaktives Prompt,
an dem du halt gucken kannst, was steht denn zum Beispiel in den Variablen
drin und dann kannst du halt auch
sagen, okay, ich gehe jetzt hier weiter oder ich überspringe
das und gucke dann wieder, was ist denn da los
und genau, also
und dann weißt du ja genau, wo du bist.
Also
das ist eine schöne Geschichte, ich weiß jetzt nicht,
seit wann das
Tracing eingebaut ist, das müsste jetzt auch irgendwann,
das ist noch nicht so lange her, glaube ich.
Ja, aber
Debugger hilft einem da schon
deutlich, ja.
Funktioniert halt auch in Django oder
so, kriegt man das über
die Webseite halt dann entsprechend schnell.
Ich glaube, das gehört auch mit der VSCode, also der Enito, der hat das
irgendwie auch implementiert. Ja, das muss ich mir auch nochmal angucken,
auch noch gar nicht richtig genutzt.
Man kann halt dann so Debug-Stops
setzen und so.
Ja, Breakpoints.
Introspection, ja genau.
Ja, ich habe jetzt noch
zwei andere wieder. Punkt drauf, die haben nichts mehr zu tun.
Zwar einmal, wie löst man Multithreading in Python?
Ja, das
funktioniert so wie sonst auch.
Also tatsächlich sind auch Threads in
Python halt tatsächlich ganz normale,
bilden sich ab auf Threads im
Betriebssystem.
Es ist halt nur so, dass
die nicht wirklich parallel
Dinge tun können
auf unterschiedlichen CPUs sozusagen. Sie können schon
parallel Sachen machen, aber halt natürlich dann
nicht so wirklich, weil
nicht gleichzeitig,
weil Sachen auf einer CPU
natürlich doch dann irgendwie immer sequenziell
abgearbeitet werden, aber
man benutzt die aber,
also daher kann man sie nicht dafür
verwenden, um
Berechnungen zu parallelisieren,
weil eben dafür müsste man es ja auf Prozessoren
aufteilen können. Das geht nicht.
Aber um
I.O. zu multiplexen,
geht das ganz hervorragend und das
funktioniert gut, kann man
dafür benutzen.
Ist jetzt nicht so die
moderne Art,
das zu tun.
Da würde man wahrscheinlich eher sowas wie Async.io
nehmen oder so. Aber
man kann auch FETs benutzen,
ist völlig okay.
Also Async.io macht dann echt das Multithreading auf Multiprozessor?
Nee, das macht kein Threading.
Async.io ist wieder eine andere Geschichte.
Was ist das?
Async.io ist, ja, kann man sagen, einmal eine Event-Loop,
sozusagen so ähnlich wie in Node.js oder so auch,
wo halt immer geguckt wird, was gibt es denn jetzt gerade zu tun oder so,
und dann macht man halt an einer bestimmten Stelle weiter.
Aber vor allen Dingen halt auch eine Syntax,
wie man das so hinschreibt, dass das automatisch gehandelt werden kann.
Also ich kann halt sozusagen
in Python Funktionen als async
deklarieren und dann
kann ich halt die Ausführungen,
wenn die zum Beispiel blockieren, halt
unterbrechen. Die werden dann später weiter ausgeführt, wenn es
halt wieder was zu tun gibt.
Und ja,
das,
aber das müssten wir, wenn man das wirklich erklären
will, wie das funktioniert, müssen wir noch mal eine Folge
zu machen.
Eben, damit kann man halt auch IOMultiplexen
und das
Ganze in einer etwas intuitiveren
Art hinschreiben, als wenn man das jetzt mit
Threading machen würde. Weil wenn man das mit Threading
mit dem Threading-Modul macht, dann
wird es sehr schnell auch sehr
unintuitiv. Und was man auch
irgendwie dabei beachten muss,
ist halt, wenn man
Tracebacks kriegt irgendwo
in Workern, die halt in unterschiedlichen
Threads laufen, das kann sehr
und also man,
das ist halt sowieso das Problem, wenn man jetzt irgendwie Dinge
asynchron tut oder so, die halt so
irgendwie,
Man hat nicht mehr so wirklich
einen linearen, der Code läuft
nicht mehr so linear durch, sondern man weiß
halt nie so genau, wo man gerade ist und was da gerade
passiert. Und wenn man da Tracebacks kriegt
und viele Threads verwendet
und dann weiß man manchmal echt
gar nicht, was da gerade passiert ist.
Manchmal kommt man in Zuständen raus, die sehr eigenartig sind
und das ist dann immer sehr hässlich zu debuggen.
Und das geht mit AsyncIO
deutlich besser. Also es ist halt
deutlich eher so, dass man
Code so hinschreibt, als wäre
er synchron quasi, aber
er dann halt automatisch mehr oder weniger
Async, also so ist das
halt in den Stellen, wo man auf
ein Syscall wartet oder so, wo es blockiert,
da macht man dann halt
an einer anderen Stelle, wo man halt
weitermachen kann, weiter. Und erst dann, wenn dann
irgendein
Lese, irgendein Read von
irgendwie Netzwerkgeschichte zurückkommt, dann geht's
halt dann da wieder weiter.
Ja, also insofern
würde ich sagen, also wenn man jetzt erst damit
anfängt, dann ist Async.io wahrscheinlich die
interessantere Geschichte, die man sich angucken sollte,
weil es mehr aussieht
wie ein normales Programm.
Aber Threading kann man durchaus
auch machen und ist wahrscheinlich sogar
ein bisschen schneller, wenn man wenig Threads hat.
Aber das ist eigentlich auch
furchtbar, das spielt alles keine große Rolle.
Okay. Ja, dann
was ist Coverage?
Oh, wuh!
Ganz anderes Thema.
Ja, meinst du das
Paket oder das Modul? Die Testabdeckung. Achso, die Coverage.
Ja, sozusagen wie viel
ja, damit gibt man sozusagen an, wie viel
Prozent des
Codes
durchlaufen wird, den man geschrieben hat,
wenn man die Tests, also man kann ja halt
gucken, auch das geht natürlich in Python ganz gut,
es gibt auch ein Module-Coverage-PUI,
das das macht, das halt guckt,
wie viele von den Zeilen wurden
denn aufgerufen, wenn ich jetzt
die Tests durchlaufen lasse von meinem Gesamtding
und das ist dann halt sozusagen, die Coverage ist halt sozusagen
die Prozentzahl und wenn ich halt 70%
habe, dann ist es halt
besser, als wenn ich 50% habe.
Wie viel sollte man denn davon haben?
Es gibt Leute, die sagen, man sollte 100% haben.
150?
Weiß ich nicht so genau,
ob das ein sinnvolles Ziel ist,
weil es dann manche Sachen sind einfach schwer zu testen
und
irgendwann wird es halt dann sehr
aufwendig und also
die ersten 80% sind es, wie das so immer ist,
die gehen relativ einfach und dann die letzten
20% brauchen dann nochmal
80% der Zeit
irgendwie, weil das halt alles so
fiese Fälle sind, die man nicht gut testen kann.
Und dann ist halt die Frage, ist es noch sinnvoll, da so viel Zeit
reinzustecken, weil den größten Nutzen
hat man dann vielleicht schon gehabt, irgendwie
in dem Code,
der halt einfach zu testen war. Aber
auch da kann man das natürlich vereinfachen, indem man
einen Code so schreibt, dass man ihn einfach testen kann.
Also manchmal mache ich Funktionen, schreibe ich Funktionen nur
deswegen, um
diese Funktionen einzeln testen zu können.
Und
ja, oder manchmal
macht es Sinn, Dinge auf eine bestimmte Art
zu strukturieren, sodass man sie halt leichter testen kann,
als wenn man jetzt irgendwie alles in einer Funktion hat
oder so, dann ist halt einfach schwer, die zu testen.
Ja, und
möglichst hohe Coverage ist natürlich gut.
Also ich bin jetzt nicht so,
ich will jetzt nicht sagen, dass 100% unbedingt notwendig ist,
aber viel wäre schon gut.
Und dann gibt es natürlich nochmal
auch feine Unterschiede, ob man jetzt nur
irgendwie durch den Code
durchgelaufen ist, hat man aber auch wirklich alle,
gibt es für jede unterschiedliche,
also wenn man sowas wie
Condition, so
Also, if-else-Geschichten hat man sichergestellt,
dass man alle Branches, die dann passieren können,
durchlaufen hat und so.
Insofern ist nicht mehr so ganz klar, was gemeint ist,
wenn man jetzt Coverage sagt.
Und ja, das kann man dann auch noch mal ...
Also, ich glaube, die ursprüngliche Geschichte ist nur so,
es ist egal, es müssen nicht alle Branches durchlaufen werden.
Und das will man vielleicht auch anders haben.
Also, ich glaube, das kann man auch bei Coverage noch einstellen.
Etwas feiner.
ja, genau. Das Test-Coverage ist halt
sozusagen ein Maß dafür, wie viel
von dem Code, der
in deiner Bibliothek ist oder so, wie viel davon
ist eigentlich durch Tests überprüft
oder ist überhaupt mal
ausgeführt worden bei einem Test.
Ja, dann haben wir fast
ja schon die letzte Frage. Ich glaube, wir sind da schon ziemlich lange wieder
heute dabei. Und zwar
auch wieder eine Hörerfrage.
Wie man die Performance, die Speichernutzung
der Codes prüfen und vergleichen kann?
Ja, also
was ich oft mache, ist tatsächlich
aber das, ich meine, ist ja die Frage, wann das
Sinn macht. Das macht eigentlich erst dann Sinn, wenn man
viel Hauptspeicher verbraucht.
Und ich mache das tatsächlich oft so,
dass ich einfach mir
die Ausgabe von Top angucke.
Und dann sehe ich schon
Systemausgabe, wie viel Speicher
noch frei ist. Ja, und wie viel
Speicher verbraucht ein Prozess.
Und wenn dann halt
irgendwas läuft, dann weiß ich ungefähr,
wie viel Speicher das verbrauchen sollte.
Und wenn das doppelt oder dreimal so viel verbraucht, dann
weiß ich, dass ich da ein Problem
habe und vielleicht nochmal irgendwas machen muss.
Es gibt aber auch systematische
Ansätze. Also es gibt
zum Beispiel auch eingebauten Profiler
in Python.
C-Profile heißt, glaube ich, das Modul.
Genau. Das kann
aber mit Memory-Geschichten nicht so viel machen.
Für Memory-Sachen
glaube ich, da nimmt man dann eher so ein bisschen
K-Cache-Grind oder sowas. Aber das
ist, ich hab das...
Aber wenn man das jetzt im Jupyter-Notebook machen möchte, weil man jetzt
keinen Pop hat oder sowas und...
Naja, du kannst dir halt von den Datenstrukturen
anzeigen lassen, wie viel
Speicher sie verbrauchen.
Da hab ich jetzt auch wieder vergessen, das wusste ich.
Also du kannst in dem Panas-Data-Frame
sagen, irgendwie meminfo oder info
oder sowas und dann deep gleich true
oder sowas, dann geht das halt, macht das
rekursiv, geht das durch
diesen Data-Frame durch und guckt halt, wie viel
Hauptspeicher brauchen da
all die Dinge, die da drin sind und sagt dir halt am Ende
eine Zahl. Und dann weißt du halt, okay, in diesem Ding
stecken jetzt noch so viele Speicher drin.
Dein ganzes
Jupyter-Notebook, also so kannst du deine einzelnen
Datenstrukturen angucken. Bei
NumPy-Arrays ist es halt viel einfacher noch.
Ich glaube, da gibt es auch eine Funktion, die einem sagt,
wie ich den Hauptspeicher irgendwie in Array verwendet.
Aber da ist es ja einfach, du kannst dir den D-Type
angucken von dem Ding und du kannst
ja auch angucken mit Shape, wie viel da drin liegt.
Und dann multiplizierst du das einfach mit,
wie viel Bit hat halt irgendwie
der Typ, den ich da verwende, mal Anzahl Einträge
und dann weißt du, wie groß es ist, weil da ist es halt sehr
einfach.
Also
so kann man bei einzelnen Sachen rausfinden, wie viel
Hauptspeicher die verbrauchen, weil das, wie viel das
ein Jupyter-Notebook insgesamt verbraucht, siehst du halt
im Top.
Und der Speed?
Ja, da brauchst du wahrscheinlich auch ein,
also kannst du natürlich auch global
das bestimmen,
indem du halt, also auf der Shell schreibe ich auf
Time einfach davor und dann
kriege ich halt dann eine Ausgabe, wie viel,
wie lange es gedauert hat
bei Jupyter-Notebook-Zellen
es gibt es auch halt irgendwie so eine Prozent-Time-Magie.
Du kannst aber, wenn du
jetzt einen Benchmark machen möchtest, dafür ist es natürlich nicht gut,
das einmal auszuführen oder zweimal,
sondern da möchte man das halt ein paar Mal
ausführen, sodass halt dann auch so Cache-Effekte
und so nicht so eine Rolle spielen.
Und da gibt es dann halt auch
Prozent-Time-It-Magie,
wo das dann halt 10.000 Mal ausgeführt wird und dann
wird dann halt Durchschnitt berechnet und dann
ist es okay, diese Funktion dauert irgendwie
üblicherweise 1,7
Nanosekunden,
äh, Millisekunden, Nanosekunden
mehr schnell für die Funktion.
Und dann weiß man halt, okay, wenn ich die jetzt
so und so oft aufrufe, dann dauert das halt.
Ja.
Okay.
Genau. Und ansonsten eben
C-Profile kann man verwenden,
wenn man jetzt noch gar keine Ahnung hat,
wenn man nachgucken möchte und dann
rauskriegen möchte, welche Funktion wird eigentlich am häufigsten
aufgerufen und wie lange verbringt
mein System sozusagen
in welchen Funktionen, dann
ist halt so ein Profile eine
ganz hilfreiche Geschichte.
Und dann, wenn man weiß, wo man Zeit verbringt,
dann kann man halt mit TimeIt zum Beispiel
in der Notebook-Zelle halt dann irgendwie
gucken, ob man das irgendwie optimiert kriegt.
Und dann kann man so die heißen
Funktionen ein bisschen
optimieren und dann sollte
das schneller werden.
Ja.
Ja.
Das war die letzte Frage, glaube ich, für heute. Ich glaube, wir sind tatsächlich
irgendwie durch. Wir haben viel geredet
über Python selbst irgendwie.
Ich hoffe, das fandet ihr wieder interessant.
Genau.
Genau, haben wir noch irgendwie Picks oder sowas?
Pick der Woche? Ja.
Bis Monats.
Ja.
Also ich hätte da noch was.
Ja, was ist dein Pick der Monats?
Und zwar, ich habe
mich letztens wieder damit
beschäftigt, eine Rechnung neu aufzusetzen
und
habe dann nochmal so
irgendwie angeguckt, ob es nicht, wie macht man
das eigentlich vernünftige Python-Entwicklungsumgebung
aufsetzen. Dazu gab es
einen
Artikel von
Jacob Kaplan-Moss, glaube ich,
einer der Django
Gründer
da, hat dazu
irgendwie meine Python-Entwicklungsumgebung
2020 Edition oder so ein Artikel
geschrieben, das sollte ich mal verlinken.
Und da dachte ich so, ah gut, dann gucke ich doch mal, was der so
macht und wie ich das so mache
und das, worauf
eine Geschichte, auf die ich da gestoßen bin, die ich
vorher nicht so verwendet habe, weiß gar nicht genau
warum. Ich habe schon davon gehört und haben mir Leute
davon erzählt, aber habe es irgendwie nicht benutzt, ist
PyEnv.
Und das war so eine der Geschichten,
die ich, also genau, das wäre jetzt beim
Tick PyEnv. Und das
ist eigentlich ziemlich cool, weil
das ist halt
ein kleines
Tool, was einem
dabei hilft, halt Python zu installieren,
was überraschend schwer ist. Es sollte eigentlich nicht so schwer sein,
aber es ist halt
ganz schön ätzend.
Vor allen Dingen braucht man Python oft
in sehr unterschiedlichen Versionen,
unterschiedlichen Arten, wie man es installiert.
Für manche Projekte brauche ich halt
Minikonda oder Konda
und
benutze auch Konda zum Installieren
von irgendwelchen Abhängigkeiten und so
und Paketen. In anderen Webentwicklungsgeschichten
wieder Virtual Envs und
da auch wieder
einen anderen Python-Interpreter,
möglicherweise halt einfach einen, der über
Homebrew gekommen ist oder
den ich einfach so installiert habe oder sowas.
Ja, und
ja, also
das war immer so ein bisschen
doof und mit PyInf ist das eigentlich relativ
einfach. Da sagt man dann halt, okay, ich hätte
gern, also der
installiert dann halt auch, PyInf installiert halt auch
Miniconda und sowas.
Und dann kann man halt sagen, okay,
PyInf install Miniconda latest
und dann hat man halt die, muss man
nicht mehr sich damit beschäftigen, da irgendwie dieses
Shell-Skript, also die
Curl in irgendwie
Shellscript zu pipen und dann
Minicon dazu installieren, sondern das passiert
alles für einen automatisch
und
man kann halt auch pro Verzeichnis dann definieren,
was denn jetzt der Interpreter
ist, der ausgeführt werden soll, wenn man jetzt da
Python eingibt. Da gibt es dann so
einen Punkt Python-Version-File
und da steht das dann halt einfach drin. Und das kann halt
auch ein
Name von einem Virtual Env sein. Dann ist man halt
in diesem Virtual Env.
Oder es kann halt der Name sein
von einem Condor-Environment.
Und das ist halt sehr, sehr cool.
Das heißt, ich hatte vorher sonst immer
einen Virtual-Env-Wrapper verwendet
und dann immer so Post-Activate-Skripten.
Einmal dann halt,
ich überlege gerade,
ob das nicht ein anderes Thema ist,
aber nee, ins Verzeichnis gewechselt
und dann noch so Dinge gemacht und so.
Und das geht eigentlich quasi mittlerweile
alles relativ automatisch
und man muss halt auch nicht mehr
work on irgendwas sagen,
sondern man geht einfach in das Verzeichnis und dann ist
gut. Also es funktioniert noch nicht alles
hundertprozentig. Das ist auch noch so eine Idee.
Ich glaube, ich packe das irgendwo
wo packe ich denn das am besten hin? Ich habe mir das
mal versucht irgendwann aufzuschreiben sozusagen, was ich
da alles tue
und was man so an hilfreichen Tools
da verwenden kann. Vielleicht packe
ich das irgendwo auf GitHub in Gist oder so.
Vielleicht haben andere Leute ja auch noch Ideen,
was man da an tollen Dingen machen kann.
Und vor allen Dingen, manche Sachen funktionieren auch nicht so ganz
sauber. Also von irgendwie
Virtual-Env nach Conda wechseln, das geht irgendwie,
aber umgekehrt geht irgendwie nicht oder so.
Weiß nicht genau, warum.
Ja, und
vielleicht wäre das mal eine sinnvolle Geschichte, das mal zusammen
zu tragen. Was muss man eigentlich machen, um halt eine ordentliche
Python-Entwicklungsumgebung
irgendwie aufzusetzen? Ja, das klingt auf jeden Fall
nach einer guten Sache. Genau.
Ja. Ja, und
genau, Python
fand ich jetzt sehr, sehr
überzeugend eigentlich und
bin ich eigentlich
dachte ich mir, warum fände ich das jetzt eigentlich
nicht schon immer sozusagen, weil das
vereinfacht doch eine Menge Sachen deutlich.
Ja, ich habe auch einen kleinen
Pick der Woche. Ich nehme diesmal
Turtle, diese kleine Bibliothek, mit der man
kleine Sachen zeichnen kann auf einer Kenntnis.
Ach, Turtle-Grafik, ja. Ja, weil da kann man tatsächlich
ganz lustige Sachen machen, zum Beispiel Kunst.
Man kann sich Algorithmen in die Mandelbrotmengen
berechnen lassen, Funktionen, und der zeichnet
dann ganz tolle, witzige Bilder,
mit denen man Computerkunst macht.
Also, unabhängig davon, dass man jetzt
eine kleine Schildkröte über den Bildschirm bewegen kann,
um einfache grafische Spielchen zu bauen.
Das fand ich sehr witzig, deswegen wollte ich das noch mal
picken. Ja, cool, cool,
cool. Ja, vielen Dank
fürs Zuhören. Egal wann ihr hört,
montags, mittags,
abends, nachts. Bleibt uns gewogen,
habt viel Spaß und wir hören uns bald wieder.
Ja, bis zum nächsten Mal. Tschüss. Tschüss.
Auf Takt
Intakt
Im Viertag soll es klingeln.
Dreiklangs, Dimensionen sind taktvoll.
Lichtspiel, Impressionen, die Farbfarbe.
Farbton, Halbton.
Und Synchron, da zu schwingen.
Drei Klangs, Dimensionen, so taktvoll.
Lichtspiel, Impressionen, so fassvoll.
Wohlklamm, Illusionen, die um uns herum tanzen.
Drei Glanzdimensionen, so taktvoll.
Licht spielt Impressionen, so farbvoll.
Klänge für Millionen überwinden die Distanzen.
Drei Klangsdimensionen, so taktvoll.
Licht spielt Impressionen, so fachvoll.
Bis zum nächsten Mal.
Bis zum nächsten Mal.
Ausgang
Abgang
Sequenzen, ohne Grenzen.
Dreiklangs, Dimensionen, so taktvoll.
Lichtspiel, Impressionen, so farbvoll.
Dreiklangs, Dimensionen, so taktvoll.
Lichtspiel, Impressionen, so farbvoll, Dreiklangs, Dimensionen, so taktvoll.
Lichtspiel, Impressionen, so farbvoll, Dreiklangs, Dimensionen, so taktvoll.
Licht spielt, Impressionen, so farbvoll, drei Klangs-Dimensionen, so taktvoll.
Licht spielt, Impressionen, so farbvoll, drei Klangs-Dimensionen, so taktvoll.