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 2er-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.
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 da 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 von Olli,
die hat ja noch geschrieben, Tipps für eine gute Syntax,
dein Top 5 oder so.
Ich, heute,
heutzutage würde ich sagen, Black verwenden und nicht mehr
drüber nachdenken.
Also einfach Black, bumm.
Also Namen vielleicht auch.
Namen sind natürlich, das sind ganz,
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 mal 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
guten Kommentaren, sollte er
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 verschreibt,
dran denken, dass
das, wenn das
jemand liest, dann halt verständlich
sein sollte, weil Code viel öfter gelesen wird,
als geschrieben.
Ja, okay.
Was ist mit sowas wie List Comprehensions?
Würdest du das bevorzugen gegenüber klassischen
loben. Nö, 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
einfacheres 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 Comprehension sehr, sehr
schnell, sehr, sehr unübersichtlich,
wo ich dann halt irgendwie stolz darauf war, so ein Statement
hingekriegt zu haben.
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 drauf guckt, der das
verstehen muss und das
unter einem gewissen Zeitdruck tut, dann
würde der sich wahrscheinlich irgendwie
Rot vor Wut.
Spaß zur Ärger.
Da gibt es
das Remote Strangulation Protocol
irgendwie zur 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
ManPages oder die
SysAdmin Recovery,
gab es eine News Group
und dann ASR,
Alt SysAdmin Recovery,
das war die News Group und dann gab es die ASR
ManPages und Tools.
Ich glaube, wenn man ManASR
sagt oder ManKnife oder
Mansnip 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
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 was irgendwie lustig.
Und da gab es auch Protokolle
und eines der Protokolle in dem Zusammenhang ist halt,
dass RSTP, RS, weiß nicht,
eben Remote Strangulation Protokoll
über Fernverbindungen.
Sehr gut, sehr gut.
Ja, 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 okay, ein bisschen
Syntax haben wir gemacht, ja, 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 Full-Second-Python geht gar nicht, weil
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, okay.
Ja, das heißt, JavaScript braucht ihr, wenn ihr Full-Tag machen wollt.
Und mit nur 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 nicht andere Sachen
wie Data und Backend so gut kann?
Naja, also wenn du eine Webseite machst, hast du halt 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 könntest du vielleicht schon 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 es ja so ein paar Framework, ne?
Grid, Materialize und so.
Naja, also ohne da was. Aber das ist
ja was anderes. Ja, also Fullstack geht gar nicht
nur mit Python. Ja, und das
ist tatsächlich auch einer der großen
Risiken irgendwie
für die Zukunft von Python, wenn das halt
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, Marcel, dann
schreibst du 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.
Import-Sys, Son of Python.
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, den Interpreter öffnen, einfach Import-Sys eingeben und abschicken.
dann seht ihr das. Then of Python, also die Prinzipien,
die man sich
darauf geeinigt hat, die in Python gelten, sollen
auch sein, wenn man die Anwendung versteht.
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.
Ja, das ist sozusagen einfach nur die
Art, wie man
relativ minimalistischer
Konsens
darüber, wie man Python-Code formatieren
sollte, vielleicht.
Wer macht das nicht, dann kommt
hier in die Python. 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 da drunter
die Klammer wieder zu, wo ich dann
sagen würde, hey, für die fünf Zeilen extra, 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 ja 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, Klammer zu, 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 Enzien, dass wir nur
89 Zeichen auf dem Bildschirm haben.
79. Ja, 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.
Und es gibt natürlich,
oder ich weiß nicht. Ja, die alten, aber nur
also die neuen.
Weiß ich nicht, ob es da, ne, ne, der Standard ist immer noch so.
Also wenn, ist auch so, wenn du, 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, ich,
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 gut.
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 Rechnerzentrum, 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.
Das heißt, wenn, dann sieht man da halt, muss man kurz
drauf aufpassen, dass es dann umgebrochene Zeilen
gibt, die automatisch vielleicht
eingruckt 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 zeichnen deswegen, weil man halt
noch eins braucht von den Zeilen.
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 unabsichtlich und hässlich, einige Sachen.
Also ich finde, DECK 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 der jetzt ganz komisch rum
irgendwie und die anderen darunter
sehen nicht so aus.
Das ist irgendwie komisch.
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,
ja, ja, ja.
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, oder so viele
Firmen haben das auch, die ja alles
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 damit lernen.
Also die Grundlagen zu verstehen, ist gar nicht so
schlicht und hat man irgendwann nicht
keinen mehr, der versteht, wie es irgendwann mal gebaut worden ist.
Es sind nur noch Leute, die dann irgendwie auf dem
Sand und der Asche von alten versunkenen
Stieten 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 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,
ist dann auch so,
wie meinte ich, über Django 3 kurz
auch
gesprochen und
Und dann hat er dann so, naja, das sind halt eigentlich zwei Zeilen irgendwie in einem Modell, wenn man das selber macht.
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, Parc-V-Resonierung muss immer stimmen und genau 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 irgendeiner, ja.
Also man kann nicht sagen, das eine ist super schlecht, das andere ist, sondern man muss halt 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 so schlecht,
wenn man halt nicht von ganz immer anfängt.
Obwohl es natürlich auch nett ist,
wenn man vielleicht erst mal Assembler lernt und dann C
und dann irgendwie 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 und das selber zu implementieren.
Ja, über die Zeit ist es natürlich so, dass auch der Level an Abstraktion, auf dem man arbeitet, wird 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 halt 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, steht das alles so ein bisschen auf tönernen Füßen, das 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.
Wenn man halt das Gebäude, den Palast aus der Sandgrube
baut, man kann tatsächlich noch ein paar Stahlträger einziehen,
das dann zu tun hat, könnte der Palast auch gehalten werden.
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, ne, 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, so, was man auch vielleicht
achten muss. Also, falls ihr noch Fragen habt, die ich nicht beantwortet
hatte, ne, schreibt uns wieder, wie immer,
hallo at pythonpodcast.de, so.
Wofür ist die InetPy?
Das ist eine gute Frage.
Ja, man braucht das irgendwie,
damit es ein Paket ist.
Ein Modul, wo ist der 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.
Interessanter Fall 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-Folder-Name
oder sowas. Und wenn da eine Inis-Pi drin ist,
dann kann man die Module, die da drin sind,
einfach aufrufen mit
seinem Import-Teil. Und dann kann man
Modul-Verzeichnis-Name, 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.
Ja, aber es ist jetzt nicht so total privat.
Ja, also es ist 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 habe ich 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 umfummeln, ich fasse meine Klassen nicht an.
Alles, was man selber schreibt,
kann man immer anders kaufordern, wie man anderes
anfasst.
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
den gecacheten 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 einem Underscore-Attribut ab.
Underscore-Cache.
Ja, oder Underscore, dieser Name dieses Attributes oder so.
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 den 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 dann gibt es ja meistens
ein öffentliches
Attribut, was man benutzen
kann und dann kann die Klasse das intern
handeln, wie sie das integriert.
Ja, im Grunde
eine Schnittstelle,
die Schnittstelle zu irgendwas.
Das gibt es 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ß
der Teufel. Und die sind aber intern
gar nicht alle mit einem Underscore.
Nö, also manche von denen kann ich auch einfach so verwenden, das ist ja
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.
Ja. Was ist eine private
und eine globale Variable und was ist der Unterschied
und wofür braucht man das?
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 in anderen Programmiersprachen gibt es da
eine stärkere Unterscheidung,
aber im Grunde ist es einfach so.
Also ich hatte es gerade so in den Anfängertagen
ganz oft so, dass ich irgendwie mir dachte,
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 eigentlich die Variablen
immer privat. Nein, nein, nein, nee,
das ist eine Verwechslung. Also du meinst lokal.
Lokal und global.
Privat und öffentlich, das ist halt genau
diese Geschichte mit dem Double Underscore.
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 oder es ist total nicht so backrested.
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.
Ja, kann man durchaus machen. Es gibt auch Fälle, wo das durchaus praktische Anwendungsfälle hat. Es kommt halt darauf an, was man damit machen möchte. Man muss das halt explizit als global markieren, wenn man das tun möchte.
und dann gibt es auch 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
und an 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 dem 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.
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 der 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.
Hinter Objektorientierter Programmierung, dass du
halt die ganze Komplexität
irgendwie verbirgst.
Hinter
ja, hinter dieser
in diesem Objekt hinter einer API
und dann das halt alles nicht mehr wissen
musst. Während wenn du jetzt einfach nur eine Variable hast,
die da 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
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 Singleton nehmen,
beziehungsweise in Python eher Borg-Pattern.
Oh, Singleton, das steht hier ein bisschen weiter unten. Ein Singleton.
Ja. 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
Spiel
die Spielfigur oder so, die dann bestimmte
Eigenschaften hat, wie eben sowas wie Lebensenergie
oder so, wenn ich garantieren
möchte, dass alle, die damit interagieren,
immer die gleiche Instanz sehen.
Es gibt nur einen, 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?
Ja, das ist, nee, eigentlich
so, weil dann kommen wir zu dem Borg-Pattern,
so wird das üblicherweise dann in Python implementiert,
ist, man macht es einfach so, dass
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 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, die
ursprünglichen Singleton-Beschreibungen, das wird einfach immer
die gleiche Instanz
retornt, wenn man halt die...
Also das heißt nie überschreiben. Das würde halt bedeuten, wenn
schon ein anderes gibt, retornt es halt das.
Retornt es 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 ist
über alle Instanzen verteilt,
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's?
Ja.
Ja, aber genau, das sind alles,
es geht immer so um State Handling
im Grunde. Das ist immer so das, und
wer manipuliert den und wie kann man
dafür sorgen, dass der, dass man
die,
den Code, der den State manipuliert,
an einer Stelle behält und so.
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
und 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
und dass man dann halt... Was ist überhaupt State?
Das, was ich,
das, was du speichern musst,
was sich irgendwie ändert.
Der Status.
Ja.
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 eine klassische...
Ja, 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 ja erst die Daten anfragen oder sowas. Das macht man dann gar nicht woanders.
Ja genau, also
so
ja, also das, was
halt sozusagen
beschreibt, in welchem Zustand deine Applikation ist.
Gehen wir jetzt nochmal aufs Spiel kurz.
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 Sonstwas-Schwert, Feuerschwert,
mit dem du irgendwie alle platt machen kannst.
Dann muss ja irgendwo gespeichert werden, dass du
das jetzt hast, dass das eine 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, was dahinter steckt.
Die interessante Frage ist, wie verwaltet man diesen
State sozusagen?
naiv wäre halt,
man hat halt zum Beispiel,
Held ist halt in irgendwelchen globalen Variablen.
Man hat halt eine Liste, die ist halt
global und 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
ein 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, dann 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, also 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, 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 irgendwelcher anderer Code irgendwas anderes tut.
Und dann passieren halt Fehler und seltsame Effekte.
Und solange man halt von dem ganzen anderen Code,
der irgendwie daran rumanipuliert, 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 anfasst,
sondern dass du sagst, okay, wir haben hier eine Klasse oder so
und bündeln wir den State, also die Daten,
und die Logik, die jetzt irgendwas damit macht
und haben dann 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
einer Klasse.
Also mit einer Klasse
definiert man sozusagen
eben eine Zusammenfassung
von 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 sage nicht so besonders an von dem Brot, der irgendwie
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. 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.
Die nächste Frage war, was ist Self?
Self ist immer das Objekt selbst.
Ja, es ist auch eine
Konvention, 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 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
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.
Wir müssen auch gleich darüber sprechen, was ein Dekorator ist.
Aber es gibt drei Dekoratoren, die
Python verwendet, die da
immer so drüber stehen. Das StaticMessage,
ClassMessage und
Property, über Property
hattest du eben auch schon. Was ist denn
jetzt da irgendwie so der kleine
Haken? 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.
Class Method ist
halt eine
Methode, die
eben nicht eine konkrete Instanz.
Das heißt, da fehlt auch Self bei.
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.
Man kann das dann auch ein Stückchen weiter treiben,
auch dann mit dem Meta-Klassenanschluss.
Also das kleinste Objekt, also jede Klasse
ist irgendwie ein Objekt und das Objekt-Objekt-Objekt
selber ist ein Objekt vom Typ-Typ.
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 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 ein Beispiel für
sowas sind, was ist denn
ein gutes Beispiel für?
Jetzt bin ich schon 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
ein. Was ist denn der beste und fließende 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 Static-Method ist halt,
dass sie dann im Namespace der Klasse
oder des Objekts aufrufbar ist oder so.
Ja, was ist jetzt in dem Vergleich eine Static-Method?
Okay.
Ja, also Static-Method
bekommt gar kein
automatisches Argument
mit, sozusagen.
Also 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
sag 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, das mit dem Manager lassen wir jetzt mal kurz
weg, da müssen wir uns schon ein bisschen langgucken. Ja, es ist nochmal
komplizierter, aber dieses Objects ist auf jeden Fall
Dingen, was an der Klasse hängt
von
und
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
ranzählen 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.
Also das könnte man... Jetzt haben wir noch Property.
Property-Dekorator, ja.
Und 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.Fubar.
Also braucht man eigentlich nicht, man könnte auch eine Methode schreiben.
Ja, aber dann müsste man 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
explizites 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 oder was auch immer, 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
Umsatz gewinnen und dann
geht das einfach schnell aus.
Also das
Get zu implementieren ist sehr, 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, irgendwas, InstanceX.fuba
gleich irgendwie.
Das ist ein bisschen komplizierter, aber
ja, geht auch so ähnlich.
Ja, also
man kann, ich weiß nicht genau, man kann mit dem Property-Dekorator
irgendwie sagen, so, das ist hier der Getter, das ist hier
der Setter oder was, ich weiß nicht genau.
Kann man dann nachgucken, wie man es braucht. Braucht man
selten. Also ich habe es ein paar Mal benutzt,
aber nicht oft.
Aber überhaupt das Konzept von Dekoratoren.
Das ist mal ganz gut. Getter-Setter bedeutet halt, dass
mal die Attribute irgendwie von außen dann
beeinflussen, setzen. Von einer Instanz
bekommt oder setzt
und zwar nicht direkt
manipuliert, sondern
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 eigentlich noch irgendwas anderes
vorher sagen. Dann muss man vielleicht nochmal erklären, was
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
Spezialsyntax.
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 haben 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 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 ein, der zeichnet ziemlich genau, was es tut.
Man hat halt...
Input und Output, der rauskommt oder beziehungsweise
reingeht, wird...
geht nochmal durch anderen Code durch und
dann
sozusagen man kann halt, 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 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, genau, nicht wirklich, wenn man Dekoratoren schreibt,
nicht das selber machen eigentlich, sondern man sollte für den Functools Reps 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 es halt eben in den Functools,
gibt es da, glaube ich, irgendwie
Funktionen,
die, wenn man die benutzt, um den Rekord-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 sowas? 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.
Hm, also
ja, also was
eventuell irgendwie
eine Gemeinsamkeit
ist, dass beides irgendwie unten drunter vielleicht
Closures verwendet, 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, ein Tipp ist,
wenn man Dekoratoren schreiben
will, aus den Funktools
die Wraps-Funktion zu nehmen
und
einfach mal so ein bisschen damit rumzuspielen.
Man braucht ein bisschen, bis das irgendwie,
bis man das so raus hat.
Ja.
Genau, 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
zum Beispiel eben
wie der Datenbankgeschichte, kann man sagen,
okay, gibt es einen Transaktions-Dekorator.
Da schreibt man einfach drüber.
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.
Ja, es ist, klar, kann man auch
machen, ja.
Ja.
Das, genau, das ist eine
Geschichte. Ansonsten,
ja, man kann auch Dekoratoren dafür benutzen,
um sich jetzt eine bestimmte Datenbankverwendung
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 Mix-In 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... Mixin sind so ein bisschen
eben, wie man
Code
wiederverwenden kann in
Klassen, ohne erben zu müssen. Weil erben
macht natürlich, das ist ja sozusagen ein ganz klassischer
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 nicht genau mit der
ursprünglichen Klasse zu tun hat, sondern...
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.
Das ist, äh,
ja, ja, warum auch nicht?
Ja, wenn
man sagt, man hat die Flügel haben wollen, man hat irgendwie eine
Klasse, die Flügel bereitstellt, dann kann man diese Flügel
jeder Klasse geben und jetzt.
Ja, macht natürlich
auch nicht immer irgendwie Sinn, aber
also, 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, ne? Irgendwie, wenn man
jetzt ein rechtwinkliges Dreieck hat, dann ist das
auf jeden Fall schon mal ein Dreieck, ne? Und ein Dreieck
ist irgendwas, was halt irgendwie...
Ja, ich finde das gar nicht so schlecht, das nämlich dem Gradius
auch vorzustellen, ne? Also die Geometrische Formen sind
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 Mixin 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.
Es 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 kennt.
Genau, man kennt meistens das Problem nicht richtig.
Und bei Mixins ist es relativ simpel.
Das ist halt so wie, keine Ahnung,
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,
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
daraus entstehen 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
ja,
diese Mixins machen halt nichts anderes, außer
irgendwie halt eine Methode sozusagen
hinzuzufügen zu einer Klasse.
Und ja,
ja und so
Vererbungen,
das macht halt mehr.
Das tut mehr, also es gibt halt
diese Basis, Basisklassen,
Basis oder sowas, da gibt es noch sowas 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, dass wenn man da, wie du sagst,
einen Fehler macht, dann hat man
Circle-Vererbung oder sowas.
Ja, das passiert 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 verschachtelte List Comprehensions
zackt oder so. Und mit Abzug Meta-Klassen
bitte? Ja, Meta-Klassen, oh ja.
Aber, ich weiß nicht,
vielleicht keine gute Idee. Also jedenfalls nicht am Anfang.
Also, 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
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.
Teufelsküche in der Schlangengrube.
Man kann das ja immer noch machen
am Schluss, wenn man dann irgendwie 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 ist 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 ja
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,
barbar.attack gleich lambda x
y z, 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
weiß ich nicht, Rassen, zum Beispiel
Echse oder Mensch oder sowas.
naja, nee, ich bin 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 das 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-Zeit 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 hinauszuzö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 Weltformel 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 Argument. Genau.
Man sagt dann irgendwie
Funktion, Klammer auf, Stern
und dann eben
Args, Argumente oder
wie auch immer das die Items, die Struktur
heißt, die man jetzt gerade in der Hand hat,
Klammer zu und dann kann man in der Funktionsdefinition
drinstehen haben, so was,
Def-Funktion, Klammer auf, A, B,
C und
muss dann natürlich alles irgendwie stimmen von der Anzahl
und so, aber das passiert dann automatisch.
Ich finde das 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 übergeben und hat dann seine Keywords.
Genau, das eben
bei normalen Positionsargumenten ist es halt
entweder man übergibt sie
Perposition 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 da
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
Sternstern. 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 erspart.
Cool.
Jetzt haben wir noch zwei Sachen, die noch
ein bisschen in diese Funktion reingehen. Wir haben ja
Funktionen, jetzt jede Menge so Sachen.
Was ist dann Lambda-Funktion? Was macht die denn dann?
Haben wir, glaube ich, auch schon einmal kurz besprochen.
Ist eigentlich nichts Besonderes.
Es 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 in Python.
Und 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 nicht 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 mit dieser Vorschleife macht, halt machen.
Aber das geht halt nicht.
Daher
braucht man halt jetzt diese temporäre
Funktion, der man jetzt auch gar keinen, gar nicht unbedingt
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
Es ist implizit, nicht explizit.
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 schreibt man halt in diese Funktion,
da 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, sondern übergibt das statt der Lambda-Funktion,
weil es ist genau das Gleiche.
Das, was man zurückbekommt von diesem Lambda, ist auch nichts.
Das heißt, Lambda braucht man eigentlich überhaupt nicht.
Nee, 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 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 Funktionen 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
Zum 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,
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 sozusagen, gib mir einen Counter, der ab 5 zählt immer.
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
irgendwie Funktionen definieren kann und 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.
Vielleicht sollte man das mal
doch nicht machen.
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
A gleich gleich B, A ist B.
Etwas ist gleich gleich none, ist none.
Ja.
Also
wenn
ich gleich gleich verwendere,
also gleich ist natürlich irgendwie Zuweisung,
aber gleich gleich, da wird halt
der Wert verglichen.
Und bei is wird verglichen,
ob es das gleiche Objekt ist.
Und deswegen sagt man zum Beispiel 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 genau. Ja, so müsste wahrscheinlich so sein.
Das könnte eigentlich gar nicht anders.
Okay, das heißt, ihr müsst halt tatsächlich,
wenn es ist, immer genau das Objekt.
Ich weiß nicht, 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.
Ja, das, 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 und 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 eines Objektes Integer wechselt.
Wenn man ein Int 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 Word 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
Dict und List und so gibt es
UserDict und UserList.
Und auch wenn ich jetzt irgendwie
selber ein eigenes Dict, das Dinge
ein bisschen anders macht als ein normales Dict
verwenden möchte, dann
sollte ich halt irgendwie von UserDict
erben und nicht von einfach nur
kleingeschriebenem Dict.
Das ist wieder wie du das nie, weil sich
schon Leute rumgekümmert haben, bestimmte Probleme zu umgehen,
auf die man dann stößt, wenn man das nicht macht.
Ja, genau, genau.
Ja.
Ja, jetzt haben wir, wir haben 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.
Wie arbeitet man richtig mit Listen
im Zusammenhang mit Funktionen, oder gibt man eine Kopie
und retournt 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
wenn ich jetzt, also
in Python habe ich eigentlich meine 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 gibt es halt
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
wenn ich jetzt einfach
nur copy
ich weiß nicht, ob
copy in built-in ist, aber wenn ich
einfach nur sage, kopier mir das mal,
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-Copy ist halt eine,
die nur sozusagen
also bei einer Liste
könnte ich mir jetzt sogar vorstellen, dass es oft,
wenn ich jetzt nochmal Lists drumherum schreibe oder so,
dass dann tatsächlich eine Kopie erzeugt wird.
Also eine Nicht-Cello-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 Cello-Kopie
und
sozusagen. Warum brauche ich dann überhaupt
eine Cello-Kopie? 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 Form Copy, Import Deep Copy.
Und dann sagt man Deep Copy,
irgendwie komplizierte, dick verschattelte Datenstruktur.
Und die geht dann rekursiv da durch
und kopiert den ganzen Kram da raus in eine andere Datenstruktur.
Und dann habe ich 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 ein bisschen mit in den Fuß schießen,
wenn man sowas ü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,
wenn man jetzt 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 dann 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 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,
ob es None ist und dann setzt man die Liste
neu. Das ist halt echt nur eine böse Fußengel.
Also das kann
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 wie man, also eine
Geschichte, wie man, also List Comprehension
macht immer eine Kopie, wenn man zum Beispiel
erzeugt immer eine neue Liste.
Ansonsten, ja, die Kopie aus dem Kopiemodul,
wenn es kompliziertere Datenstrukturen sind, dann muss man
sich das nicht selber, also oft ist es ja, ich meine, es ist ja
wirklich kompliziert, wenn man da halt
was, ja, 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, was in den, es gibt ja
unterschiedliche Arten zu programmieren,
ja, so imperativ. Ich würde auch Python
eher, auch wenn man es auch mit Berechtigung
sagen kann, es ist 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 Dikt übergeben bekommt,
das dann irgendwie dann ändert
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, man muss halt,
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 irgendwelche, alle
Operationen geben immer Kopien zurück,
aber das kann auch ganz schön in den Hauptspeicher
gehen und manchmal muss man dann schon sagen, so, ja,
hier bitte nicht kopieren. Das geht einfach nicht, passt da 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 Dirty. 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. Also dann kommen wir direkt
das gekonnt, schließt 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, also 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, ja, ist halt sehr effizientes
Ding und einen Riesenhaufen
Probleme lassen sich dadurch schon lösen.
Also wenn man das ordentlich verwendet,
dann kriegt man da so ein 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 Tupel, das Datenschutz, wenn man eine Listen hat?
Also warum ist das überhaupt?
Ja, Tuppel 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 Listen.
Klar, das geht auch mit Listen, aber ich weiß nicht,
ich überlege jetzt gerade, ob es einen tieferen Grund gibt,
warum Argumente
ein Doppel sind.
Also,
ja,
generell. Also, Dicky 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 wie String, wobei Listen und Dicts ist halt auch so das,
was man in allen Programmiersprachen irgendwie
oder vor allen Dingen in allen Skriptsprachen
irgendwie eingebaut findet.
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.
In Perl heißt es halt Hash und Array.
In PHP heißt es Assoziatives Array.
Und 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, weil das halt,
damit kannst du halt schon eine Menge machen.
Und Tuple 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 Z in Python.
Ja. 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 Dicts
gibt, aber
zum Beispiel von Z gibt es halt Frozen Z, eben
auch für solche Fälle, wie du möchtest, dass das
irgendwie als Key in Dict ist oder so.
Und den kannst
du halt dann nicht mehr verändern.
Vielleicht gibt es auch so etwas 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.
Okay, wann nutzt man denn
NumPy-Arrays? 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 verschicken 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
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 einfach, 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, ist 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
so ein bisschen auch wieder en vogue.
Auch hässlich.
Ist aber 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 Jason gemacht worden sind. Und Jason ist
das, was rauskommt, wenn man alle Fehler ignoriert,
die bei 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,
da 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, du kannst halt innerhalb von XML, gibt es halt sowas wie Kommentare, wie willst du XML-Kommentare quoten? Das geht überhaupt gar nicht. Und das heißt, wenn du jetzt zum Beispiel in XML, 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 es ist halt so, es kann doch nicht sein, dass daran keiner gedacht hat, dass das jetzt nicht geht. Es 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, schrecklich. Und Jason ist aus dieser Perspektive für mich weniger schrecklich. Also 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,
da gibt es dann sowas, da gibt es ein etwas besseres Format,
Message Pack nennt sich das, das kann man halt so
ähnlich wie Jason, bloß
binär so, dass
das halt irgendwie
nicht kaputt gehen kann bei der Übertragung oder nicht so
leicht kaputt gehen kann wie Jason.
Ja,
und naja,
aber Jason 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.
Es gibt noch in
Python selber, wenn ich jetzt überlege,
gibt es noch eingebaute Geschichten, es gibt noch
Marshall das Modul ist, macht sowas ähnliches wie
JSON, bloß halt
binär. Das ist auch 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
ja sowas wie Pickle.
Und Pickle kann man auch schicken als binär-File.
Genau, man kann
verwandelt halt ein komplettes Objekt
zum Beispiel in einen Binären-String
und dann schickt man den irgendwie übers 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, halt irgendwie
irgendwas Gepickeltes schickt, da kann
beliebiger Code drin sein.
Also wenn man das anpickelt, dann
führt man das aus, was da drin steht.
Das heißt, ja, das sollte
das sollte man sich
klar machen, dass das...
Genau, dass man
also, ja, irgendwas
anpickeln,
was einem jemand gibt, ist so wie irgendwie
Code ausführen, die einem jemand gibt.
Ein Paket öffnen, was man nach Hause geschickt bekommen hat, da kann auch
eine Briefbombe drin sein, man weiß es nie so genau.
Das ist immer auch beim Essen,
wenn man isst, was man nicht kennt, dann immer Vorkost
da daneben.
Ja.
Man weiß es nie so genau.
Die Paranoia kann ja beliebig weit getrieben
werden. Genau, genau, genau.
Pickel, lass mal überlegen, gibt es noch, es gibt
dann noch diverse, es gibt dann noch
für den wissenschaftlichen Bereich ein paar Sachen, es gibt noch
HDF5,
Net, wie heißt das Ding, NetCD,
ich habe es jetzt wieder vergessen,
wie der Standard ist,
also wie, ja, es gibt so eben für
wissenschaftliche Daten, gibt es noch Standards,
wie man, wie man
Sachen speichert, die noch so ein bisschen anders sind.
Eine CDF, glaube ich, ist das.
Und 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
nochmal eine eigene Möglichkeit, wie man sie serialisieren kann.
Man kann die auch Memory-Mappen
ähm,
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 bringen.
Aber, äh, 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.
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, am Memory Management hatten wir schon mal
gesprochen, ich glaube, in einer der ersten Folgen, da haben wir ja über den JIT
und den GIL gesprochen, an den
Just-in-Time-Compiler und den
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...
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, ich nenne es jetzt mal
Deep-Debugging, das heißt, man kann
Deer auf irgendwelche
Spawn 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 dann da genauer rein. Naja, ich glaube, das ist schon,
also Help zeigt halt den...
Also was macht man, Help ist eine Funktion, die man
außen rum schmeißt und was, was zurückkommt, oder?
Ja, aber das,
also an den Objekten hängen halt auch immer Dinge
dran, also zum Beispiel man an dem Funktionsobjekt
hängt halt auch immer 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,
zumindest kann man sich dann, zeigt es auch
die Funktion Signature, glaube ich, an noch.
Was gibt es denn noch?
Mehr verwende ich eigentlich auch
praktisch nicht.
Die ist MRO, ne?
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,
Meta-Attribute irgendwie von den Klassen dran hä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. 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 vielleicht genau, welches von den
Dingen aufgerufen worden ist,
von den Methoden, die man jetzt in reiner Weise überschrieben hat
und was da eigentlich hinter steckt, 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
Debugger zu verwenden.
Ja, welchen würdest du da empfehlen?
PDB ist halt so das, was, und man kann ja auch
inzwischen... Was macht PDB? Also der stoppt
den Code zur Ausführzeit, 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 du halt einfach deinen Code rein
und dann hast du da halt ein,
stoppt halt die
Ausführungen an der Stelle und du hast halt,
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, wann das
eingebaut ist, 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.
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 nicht 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.
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 I.O. nehmen oder so.
Aber man kann
auch ZSATs benutzen, ist völlig
okay. Also Async I.O. macht dann echt
das Multithreading auf Multiprozessor? Nein, das macht kein
Threading. Async I.O. 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,
eine Folge zu machen,
eben, damit kann man halt auch
IO multiplexen
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
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, also
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, 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 Async.io 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 einen Syscall wartet oder so, wo es blockiert, da macht man halt an einer anderen Stelle, wo man halt weitermachen kann, weiter. Und erst dann, wenn dann irgendein Read von irgendwie Netzwerkgeschichte zurückkommt, dann geht es 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 ach, das ist eigentlich auch furchtbar, das spielt
keine große Rolle.
Ja, dann was ist Coverage?
Ganz anders.
Ja, meinst du das Paket oder das Modul?
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,
das geht natürlich in Python ganz gut,
es gibt auch ein Modul-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 dann halt sozusagen
die Coverage ist halt sozusagen die Prozentzahl.
Wenn ich halt 70 Prozent habe, dann ist es halt
besser, als wenn
ich 50 Prozent habe. Wie viel sollte man denn
davon haben? Es gibt Leute, die sagen,
100 Prozent 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 Prozent sind
wie das so immer ist, die gehen relativ
einfach und dann die letzten 20 Prozent
brauchen dann nochmal 80%
der Zeit irgendwie, weil
das dann 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 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's
für jede unterschiedliche, also
wenn man sowas wie
Condition, so If-Else
Geschichten hat, werden auch wirklich,
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 nochmal, 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.
Aber 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 ich meine, es 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 Pandas DataFrame 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 DataFrame 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 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, welche Hauptspeicher
irgendwie ein Array verwendet, aber da
ist es ja einfach, du kannst dir den D-Type angucken
von dem Ding und du kannst dir 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ß das ist, weil da ist es halt sehr einfach.
Also so kann man
bei einzelnen Sachen rausfinden, wie viel Hauptspeicher die verbrauchen,
weil wie viel das ein Jupyter Notebook
insgesamt verbraucht, siehst du halt im Top.
Wie viel der Speed?
Ja,
da brauchst du wahrscheinlich auch,
kannst 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, das 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 dann 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 dann, da gibt es
dann halt auch Prozent-Time-It
so 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
wäre 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,
mal 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
sozusagen die heißen Funktionen
ein bisschen optimieren und dann
sollte das schneller werden.
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.
Ich hoffe, das fandet ihr wieder interessant.
Genau.
Ja, haben wir noch irgendwie Pics oder sowas?
Pic der Woche?
Ja.
Bis Monats.
Ja.
Also ich hätte da noch was.
Ja, was ist dein Pic des Monats?
Und zwar, ich habe mich letztens wieder damit beschäftigt,
einen Rechner neu aufzusetzen
und habe dann nochmal so irgendwie angeguckt,
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 einen Artikel geschrieben, da 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 ich da, 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, mir haben 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, 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 Conda
und benutze auch Conda zum
installieren von irgendwelchen Abhängigkeiten und so
und Paketen. In anderen
Webentwicklungsgeschichten wieder Virtual Envs
und da auch
wieder einen anderen Python-Interpreter,
jetzt 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 PyEnv ist das eigentlich
relativ einfach. Da sagt man dann halt, okay,
ich hätte gern, also
der installiert dann halt auch, PyEnv installiert
halt auch Minikonda und sowas.
Und dann kann man halt sagen,
okay, PyEnv install Minikonda
latest und dann hat man halt die,
muss man nicht mehr sich damit beschäftigen,
dieses Shell-Skript,
irgendwie Curl in irgendwie Shell-Skript
zu pipen und dann Minikonda
zu 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 Conda-Environment.
Und das ist halt
sehr, sehr cool. Das heißt, ich hatte
vorher sonst immer
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 zusammenzutragen. Was muss man eigentlich
machen, um halt eine ordentliche Partner-Entwicklungsumgebung
irgendwie aufzusetzen?
Ja, das klingt auf jeden Fall nach einer guten Sache.
Genau.
Ja, und genau,
Pines fand ich jetzt sehr, sehr
überzeugend eigentlich und
bin ich eigentlich
dachte ich mir, warum finde 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 Kenner.
Ach, Turtle-Grafik, ja. Ja, weil da kann man tatsächlich
sehr 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 nochmal
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.
Untertitelung des ZDF, 2020
Auf Takt
Im Takt
Im Für-Takt
Soll es klingen
Drei Klangs-Dimensionen
So taktvoll
Lichtspiel, Impressionen, Gefahr, Farbton, Halbton und Synchron
Dazu schwingen, Dreiklangs, Dimensionen, Kontaktvoll
Lichtspiel, Impressionen, so fassbar
Wohlklang, Illusionen, die um uns herum tanzen.
Dreiklangs, Dimensionen, so taktvoll.
Lichtspiel, Impressionen, so farbvoll.
Klänge für Millionen, überwinden die Distanzen.
Drei Klangsdimensionen, so taktvoll, Lichtspiel, Impressionen, so fachvoll.
Bis zum nächsten Mal.
Untertitelung des ZDF, 2020
Ausklang
Abgang
Sequenz
Drei Klangsdimensionen, so taktvoll Lichtspiel, Impressionen, so farbvoll
Drei Klangsdimensionen, 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
Lichtspiel, Impressionen, so farbvoll
Dreiklangs, Dimensionen, so taktvoll
Untertitelung des ZDF für funk, 2017