Transcript: Was, wenn alles ein dict wäre?
Full episode transcript. Timestamps refer to the audio playback.
Ja, hallo, liebe Hörerinnen und Hörer, willkommen beim Python-Podcast, Episode 36.
Heute wollen wir mit euch ein bisschen über die technischen Implementierungsdetails von Dictionaries reden.
Jochen ist natürlich wieder da. Hi, Jochen.
Hallihallo, Dominik.
Dominik, genau. Und heute ist auch wieder Johannes dabei. Hi, Johannes.
Hallo zusammen.
Ja, moin.
Ja, wir fangen wie immer ein bisschen News aus der Szene an und was uns sonst noch so einfällt.
Und dann gehen wir so ein bisschen in das Thema rein.
Ja.
Also du wolltest unbedingt noch über den Copilot reden,
habe ich gehört.
Ich wollte das.
Ja, ich auch.
Der Jochen ist derjenige, der immer darüber sprechen möchte.
Ja, wir haben schon zweimal darüber gesprochen.
Aber jetzt hat auch Jochen ihn ausprobiert.
Jetzt hat auch PyCharm jetzt auch Copilot.
Deswegen, genau.
Genau, ich habe irgendwann die erlösende Mail von GitHub
bekommen, sodass ich jetzt im Beta-Programm auch mit drin bin.
Und genau, da muss ich das natürlich direkt mal ausprobieren.
Und ich hätte da eigentlich gar keine so hohen Erwartungen,
obwohl du immer schon davon so vorgeschwärmt hast.
Ja, du hast immer gesagt, ach, was für ein Quatsch,
das ist ja völlig egal.
Das kann ja nicht, also wenn man jetzt irgendwie so
durchschnittlichen Code davon irgendwie in den Leuten
kriegt, das kann ja nichts
taugen. Aber
ich muss sagen, ich bin doch
sehr überrascht, dass das manchmal wirklich, wirklich
hilfreich ist.
Sogar Jochen findet das hilfreich.
Ja, ich finde es auch sehr cool. Also ich finde vor allem
dieses Autocompletion cool. Er lernt irgendwie aus seiner eigenen
Codepace und weiß so ein bisschen, was du als nächstes vorhaben
könntest oder macht manchmal so einen guten Vorschlag.
Ist natürlich nicht immer, ist auch nicht immer
richtig, aber manchmal ist erstaunlich richtig.
Ja, und manchmal findet man halt
Dinge dadurch erst,
die man, also ich habe, ich mache
jetzt manchmal auch so ein bisschen
JavaScript beziehungsweise TypeScript
und
manchmal weiß ich einfach nicht, wie Sachen gehen.
Also ich habe keine Ahnung, wie das geht und dann fange
ich irgendwie mit einem variablen Namen an
und dann kriege ich so einen ganzen Codeblock
und der tut genau das, was ich eigentlich machen wollte.
Ja genau, das ist halt richtig.
Also du musst halt wirklich aufpassen, was für Namen du
in den Dingen gibst. Wenn du dir gute Namen gibst, ist es ja viel besser,
als wenn du schlechte Namen gibst.
Muss man sowieso aufpassen und immer gute Namen
Genau, aber wenn man das dann halt macht und dann auch einen guten Docstring schreibt oder einen Kommentar dazu, dann lernt er sogar noch aus diesen Docstrings, aus den Kommentaren was dazu.
Oder halt, also was halt bei mir voll gut funktioniert, ich mache halt den Methodennamen beispielsweise oder den Klassnamen oder die Funktion und die Argumente und typen und dann weiß er ziemlich oft, was zu tun ist, wenn ich den Docstring noch mache.
Dann schreibe ich im Docstring rein, was er tun soll und dann, der Vorschlag, der ist schon echt gut.
Also auch, da gibt einer halt auch Implementierungsvorschläge, an die man vielleicht nicht gedacht hat oder sowas schon.
Ja, also da, das ist durchaus sehr beeindruckend.
Und ich weiß, warum Jochen den gut findet, weil er sich ja immer selber am eigenen Code-Repo orientiert und er orientiert sich an Jochens eigenem Code und dann denke ich auch natürlich immer, oh, was für ein toller Vorschlag.
Ja, großartiger Stil.
Also Kritik würde ich sagen, es ist auch besser geworden, wenn man diese Nightly-Version nimmt.
Ich habe zuerst die Standard-Version genommen und man kann halt die aktuelle Bleeding-Edge-Geschichte nehmen. Die ist, finde ich, nochmal ein gutes Stückchen besser. Was manchmal nicht so gut funktioniert, also womit Copilot halt irgendwie unerwarteterweise, weil man denkt, das ist eigentlich eine einfache Geschichte, große Probleme hat, wo er deswegen große Probleme hat, ist Klammern.
Also die Klammern richtig zu setzen.
Also zum Beispiel zu machen.
Das macht eigentlich fast nie die Klammern richtig zu.
Oder halt irgendwie, dass das halt
nur Sinn macht, wenn es runde Klammern sind.
Manchmal macht er auch einfach eckige Klammern bei mir.
So an Stellen, wo Funktionen aufgerufen werden.
Und dann ist das natürlich, das funktioniert halt nicht.
Kannst du das nicht erklären,
dass das doch irgendwie diese neuronalen Netze,
weil die halt nicht genügend Zustand für sowas haben, oder?
Ja, man muss denen halt irgendwie
die Syntax sozusagen irgendwie so einprügeln,
dass sie das halt nicht, dass das nichts Unscharfes
ist oder, aber das funktioniert
vielleicht nicht so richtig. Also meistens funktioniert es ja auch.
Test durch valide Sonntagslaufen oder sowas, das wird ja schon gehen.
Ja, aber prinzipiell hat dieses Netz ja kein Verständnis von
ich habe Endklammern geöffnet und muss
jetzt Endklammern auch wieder schließen in der richtigen Reihenfolge.
Ja gut, aber du kannst ja alle Vorschläge aussortieren, bei denen das
nicht stimmt oder du kannst ja danach noch auditieren oder
sowas. Ja, ja klar, also es ist jetzt auch kein großes
Problem, nur das ist halt irgendwie so ein bisschen
erstaunlich, wo man sich denkt so, naja, also das Schwierige,
den schwierigen Teil, den kann es eigentlich überraschend
gut, nämlich irgendwie rausfinden,
was man da machen wollte und dann den Code schreiben,
der zumindest so aussieht, als würde er das richtig tun.
Und dann macht er Klammerfehler.
Und dann kommen halt so Dinge, wo man sagt,
eine IDE kann das ja schon, die Klammern richtig setzen.
Und das geht dann nicht mehr.
Aber ich meine, das sind Sachen,
die wird man halt mit der Zeit in den Griff kriegen,
denke ich mal.
Und dann ist das schon echt beeindruckend.
Was man auch mal machen muss, ist so User-Daten.
Beispielsweise machst du irgendwie eine JSON auf
und dann machst du einen Namen,
eine E-Mail-Adresse oder sowas und ein Passwort
und dann machst du Autocomplete.
Da gibt es ja halt eine Liste von Usern
irgendwie, die mit dem Nutzernamen
Passwort und so, das war schön.
Das war dann die Frage, sind die generiert?
Generiert oder ja, oder sind die generiert oder echt?
Man weiß es aber nicht so genau, von wo
die sind. Das sind alle gelernt.
Ja, es ist wohl auch, wenn man so Zahlenfolgen
eingibt, dann gibt er einem interessante Instruktionen.
Das ist ein Screenshot
gesehen, wo dann russische Funktionsnamen
dazukamen.
Also, okay. Ja, ich bin ja mal gespannt,
was dabei rauskommt, wenn man so was
man anfängt irgendwie so 3.1,
4, 1, 7.
Ja.
Ja.
Ja, ja, vielleicht, vielleicht.
Also, ja, das ist ja...
Das ist noch keine AGI, das ist noch keine generelle
Intelligenz, glaube ich.
Da habe ich letztens, ach ja, ich komme vom Holzen aufs
Stöckchen, aber vielleicht ist das ja auch nicht so uninteressant,
wieder einen ganz netten
Podcast-Episode gehört mit
Lex Friedman,
Steven Wolfram.
von Wolfram Alper, interviewt hat, genau.
Ja, der ist ja so ein Wunderkind und dann so ein bisschen
hinter den Erwartungen. Eine sehr kontroverse Persönlichkeit.
Ja, polarisierend.
Warum? Jetzt musst du das genau aufklären, direkt.
Ja, es gibt Leute, die lieben ihn total und der macht ja auch
viele gute Sachen, aber es gibt Leute, die
hassen ihn auch total, weil der halt auch
seine Meinung für
sehr wichtig hält. Achso, okay.
Wir wollen ja die Gründe und Anekdoten auch hören.
Es geht um seine Meinung, die er präsentiert.
Ja, und er ist auch
so ein, er hat so ein paar
interessante Fixierungen. Der findet, dass die ganze Welt
aus State Machines besteht und muss alles mit
State Machines machen.
Und Rule 34 ist das einzige,
was...
War das nicht die andere Nummer?
War das nicht Rule...
Rule 38 oder so?
Das ist die...
Ja, diese 30er-Regeln, also das ist so eine Klasse
von...
State Machines.
Und die kannst du durchnummerieren und die haben
eine natürliche Ordnung und dann
findest du halt irgendwann eine, die eine universelle
Turing-Maschine ist im Wesentlichen.
Stephen Wolfram sagt halt, mehr oder weniger,
der schreibt ganze Bücher darüber, was diese
State Machine alles kann und dass die das Universum
enkodiert. Und das ist
natürlich,
wenn du die gesamte Wissenschaft
umstellen willst auf State Machines.
Ich habe immer noch keine Ahnung, was Rule 38 ist, aber
das Urban Digitry hat mir gesagt, Rule 38 ist
a prison offense, in which someone is
muster waiting in public.
Ah, ja, okay.
Also, wenn du mal viel Spaß hast mit so einem
Private Mode an, hast, dann google doch mal
Rule 34, das ist glaube ich
die, if it exists,
there's porn of it, glaube ich.
Das ist auch irgendwie eine sehr wichtige
Regel und tatsächlich stimmt sie halt einfach immer.
Aber... Leider,
leider erstaunlicherweise.
There's a type of porn, there's a website for it.
Ach so, okay. Das ist auch Rule 38.
Rule 30
sagen die. Okay, aber das sind
beides nicht die Regeln, die ich jetzt gerade meinte.
30 ist es.
genau, nee, aber genau, um diese Dinger ging es
natürlich bei der Episode auch und
also ich finde das schon interessant, ja, ich meine
das ist ja, also er hatte irgendwie, Leute hatten
hohe Erwartungen an ihn, weil er war halt so ein Wunderkind
und dann ist aber irgendwie
dann doch nicht irgendwie so wirklich so
Einstein
einsteinmäßige Ausmaße haben seine
Theorien da jetzt nicht angenommen, sondern er
so ein bisschen hinter den Erwartungen zurückgeblieben
und aber tatsächlich
ist er ja genau eben der Meinung
er hat ja ein Buch geschrieben, das hat auch schon so
Titel, New Kind of Science.
Das, ja,
den kann man ja auch nur nehmen, wenn man denkt, da hat man jetzt mal
echt was gefunden.
Ja, hat ein gewisses Selbstbewusstsein.
Aber er hat ja auch coole Sachen gemacht, also so ist es
nicht. Also es ist nicht nur...
Er ist halt auch super, ungeheuer produktiv.
Er hat so ein Diagramm veröffentlicht
von wann er E-Mails schreibt und der hat
eigentlich immer 18-Stunden-Tage und
manchmal hat er auch 24-Stunden-Tage.
Er erschlägt
es einfach durch Produktivität, diese
ganzen Kritikpunkte.
Ja, also er hat ja auch so eine Firma, die macht Mathematiker, auch eine super Software, also ja.
Ja, oder eben Wolfram Alpha.
Und Wolfram Alpha, genau, ja, und ja, auch die Firma so zu nennen, also naja gut, aber das ist, er macht ja wirklich cooles Zeug, also so kann man eigentlich auch nichts sagen und das fand ich so ganz interessant, weil es jetzt, weil er auch da, weil kam das Thema auch auf Pi, ich meine, das ist ja auch so eine Zahl, die einem ab und zu mal irgendwie über den Weg läuft.
und er... Du meinst Tau halbe?
Ja, genau.
Ja, stimmt. Tau ist dann vielleicht etwas, was man
häufiger noch braucht als Pi.
Und genau,
wie jeder weiß, ist das Ding halt
transcendent rational
und
hat eine Menge super interessante Eigenschaften,
aber so fundamentale Sachen,
die man jetzt, wo man denkt, das müsste man doch eigentlich
darüber wissen, also wie zum Beispiel sowas wie
kommen denn alle
Ziffern in der Dezimalbruchentwicklung von
Pi mit der gleichen Wahrscheinlichkeit vor? Also ist
Pi normal oder nicht?
Das weiß man halt nicht. Und zwar so
gar nicht. Und hat auch gar keine Ahnung, wie man das irgendwie
hinkriegen könnte. Dabei ist die Regel, die jetzt
Pi erzeugt, eben auch ziemlich einfach
eigentlich. Und dann ist es
doch irgendwie überraschend, dass dabei eine Ziffernfolge
rausfällt, die einmal so total zufällig aussieht,
wo man nicht drüber sagen kann,
jetzt okay, nicht mal die
Verteilung der Ziffern da drin sagen kann.
Und die so aussieht, als wäre sie,
als könnte man wirklich nicht, man kann es halt
auf nichts anderes reduzieren. Man kann da drin,
findet daran keine Muster oder
da kommt einfach alles, was es überhaupt
an Mustern irgendwie gibt, kommt wohl offenbar daran
vor. Das ist halt
die Frage ist halt, wie kommt
aus so etwas, aus so einer einfachen
Regel, wie man Pi bilden kann,
warum fällt da plötzlich so ein ganzes Universum raus?
Ja, das ist ja
im Wesentlichen das, was der Wolfram auch sagt
mit seiner Regel 30. Das ist ja eine ganz simple
Regel. Das ist die 30. die du ausprobierst,
wenn du sie nach seiner Ordnung machst und dann kommt so
mordsmäßiges Chaos raus und alles, was du dir vorstellen
kannst.
Das ist so eine generelle Sache in der Mathematik.
Irgendwann mache ich da auch mal noch einen längeren Diskurs drüber.
Dass man mathematisch gesehen aus sehr einfachen Regeln,
wo man denkt, die sind einfach genug, um sie im Kopf auszuführen,
Dinge produzieren kann, die völlig unabsehbar sind.
Und völlig überraschend auch,
weil sie eben nicht mehr sich an die Regeln halten,
sondern weil sie dann irgendwelche chaotischen Sachen produzieren.
Und das ist was sehr Erschreckendes und es ist aber auch gleichzeitig was sehr Schönes in der Mathematik, weil man da eben Dinge finden kann, die einen völlig überraschen, auch aus den einfachsten Bausteinen raus.
Also um das nochmal so zusammenzufassen, du hast gerade dich darüber beschwert, dass die Wahrscheinlichkeitsverteilung des Auftretens von einer Nachkommastelle von Pi in der Gesamtsumme aller Nachkommastellen von Pi, die bekannt sind, nicht bekannt sind.
Nicht bekannt sind, überhaupt nicht bekannt sind, alle. Also die kannst du ja nicht kennen.
Aber man weiß halt nicht.
Es könnte ja sein, dass irgendwann keine Neunen mehr vorkommen.
Einfach gar keine mehr.
Ist das normalerweise so?
Nee, ist eben nicht normalerweise so.
Aber es könnte sein.
Wir können es nicht ausschließen.
Das ist die Sache, was der Jochen sagt.
Keine Ahnung.
Und das ist überraschend,
dass man da so gar keine Ahnung hat.
Weil man denkt so, naja, das müsste man doch jetzt irgendwie,
wenn man die Regel wie Pi entwickelt wird,
hinschreibt und eine Funktion wie Pi ausrechnet.
Das ist wirklich so ein paar Zeilen.
Also muss man diese Zeilen nur ganz, ganz lange und genau angucken und dann muss einem doch klar sein, okay, da irgendwie ne neun, die kommen genauso häufig vor wie alle anderen auch.
Oder zumindest es kommt immer mal wieder ne neun vor, das ist ja schon ne Aussage, die sehr schwer zu treffen ist.
Ja, aber das ist doch im Endeffekt, reduziert sich das doch runter auf das Halting-Problem, oder? Also wenn du das lösen kannst, dann kannst du auch das Halting-Problem lösen.
Was ist das Halting-Problem und was ist das Tau-Halbe?
Tau halbe ist Pi. Das gab es vor einer Weile mal, das Tau-Manifest, wo jemand behauptet hat, Pi ist eigentlich die falsche transzendente Zahl. Die richtige transzendente Zahl ist eigentlich Tau und das ist zweimal Pi, weil dann ganz viele so quadratische Formen eben einen Faktor 2 verlieren, der diese Formen einheitlicher macht.
Es gibt auch ein Gegenmanifest gegen dieses Tau-Manifest, das quasi das Gegenteil behauptet und sagt, das ist alles Quatsch, weil es gibt genauso viele Dinge, die mit Pi schöner aussehen als mit Tau. Deshalb ist es so ein Witz unter Mathematikern, wo man Leute leicht auf die Palme bringen kann.
Dann aber einfach nochmal kurz die ganze Unbelegung. Was ist denn Pi?
Pi ist das Verhältnis zwischen dem Radius eines Kreises und der Fläche des Kreises.
Und das heißt, wenn ich einen Kreis mit einem Radius 1 habe, dann hat er die Fläche Pi.
Und bei den meisten geometrischen Figuren ist es so, dass die Fläche sich relativ leicht berechnet.
Also wenn ich ein Quadrat habe und das hat Seitenlänge 1, dann hat es die Fläche 1.
Und wenn ich ein Dreieck habe, dann hat es die Fläche 1,5 mal 1.
Dann gibt es irgendwelche ganz leichten Formeln.
Beim Kreis ist es leider anders.
Da kommt eben die Zahl Pi raus.
Und die Zahl Pi ist eine transzendente Zahl.
Das heißt, die ist eine nicht-rationale Zahl.
Es gibt keinen Bruch, der Pi korrekt darstellen kann.
Es ist auch eine transzendente Zahl.
Das heißt, die ist nicht algebraisch.
Das heißt, es gibt auch keinen Polynom, was Pi als Lösung hat.
Und das macht es zu einer ganz besonderen Zahl, weil die Zahlen, die man normalerweise so kennt, Wurzel 2 und Wurzel 3 und Wurzel 5 und Wurzel 7 und 2 mal Wurzel 5 halbe und so weiter, das sind alles algebraische Zahlen. Das heißt, die sind Lösung von irgendeinem Polynom und die haben dann eben diese Eigenschaft, dass ich die in dieses Polynom einsetzen kann und dann kommt 0 raus.
Das geht mit Pi nicht.
Es gibt für Pi kein Polynom, was Pi als Lösung hat.
Und deshalb ist es eine ganz besondere Zahl.
Nee, es gibt keins.
Gibt es nicht? Also es ist bewiesen, dass es nicht gibt?
Ja, weil es transzendent ist.
Und tatsächlich der Beweis, dass Pi transzendent ist,
ist eine sehr schwierige Sache.
Ist auch noch gar nicht ungeheuer lange her.
Aber das Ergebnis ist eben sehr wichtig,
weil das eine Klasse von Zahlen ist,
von denen es wesentlich mehr gibt als von anderen Zahlen,
die für uns aber aus unserem menschlichen
Verständnis her sehr schwer erreichbar sind,
weil wir eben Brüche gewohnt sind und
Wurzeln von irgendwas, also
algebraische Zahlen,
das sind aber tatsächlich so auf eine
gewisse Art und Weise die wenigsten
reellen Zahlen.
Es ist eben eins von diesen
bekannten Beispielen für eine Zahl, die
sich anders verhält, als man denkt.
Und deshalb ist sie in der Mathematik sehr wichtig,
weil sie eben eine
transzendente Zahl ist.
Es gibt noch ähnliche Zahlen, es gibt noch E.
Die Eulersche Zahl?
Die Eulersche Zahl, genau.
Und die hat nicht ganz so eine einfache Erklärung.
Sehr gut, Dominik.
Die hat nicht ganz so einfache Eigenschaften,
die ist nicht ganz so einfach zu erklären.
Aber ist auch transzendent.
Man weiß auch nicht, ob es normal ist.
Man weiß auch da die Verteilung der Sachen alle nicht.
Das heißt, diese Zahlen, die sind sehr, sehr schwer in den Griff zu kriegen,
obwohl es eigentlich sehr viele davon gibt.
und ja
das ist halt leider so
ja und genau
also ja in gewisser Weise haben die jetzt auch was
mit eben diesen ganzen
theoretischen Informatikgeschichten zu tun
weil sie sozusagen in gewisser Weise
berechnungstechnisch
irreduzierbar sind sozusagen also man kann halt
nicht
keine geschlossene Form
man muss sie tatsächlich ausrechnen
genau sonst kriegt man sie
halt nicht in den Griff. Und das Problem ist, das ist halt
teuer, die auszurechnen, da muss man halt
Ja, und das ist ja auch so ein bisschen ein Sport,
dass die meiste
Anzahl Stellen von Pi ausgerechnet ist.
Ja, gab es letztens irgendwie wieder eine Nachricht, dass da
60 Millionen Stellen oder weiß ich nicht
oder noch mehr, ich weiß gar nicht genau, wie viele.
Genau, also da kommt man dann halt wirklich sehr schnell in solche
Bereiche rein, wo es dann gar nicht mehr so sehr
um Prozessorleistung geht und gar nicht so sehr um
Smarthand geht, sondern da kriegst du dann so richtig die Big Data
Probleme. Wie schaffst du das auf einer Zahl
zu operieren, die 60 Milliarden Stellen hat?
Ich habe mich mal kennengelernt, der hat sich als Hobby
Aufgabe gemacht, Nachkommastellen von Pi
auswendig zu lehren, hat, glaube ich, die ersten 250
aufsagen können.
Okay, das ist schon mal nicht so schlecht. Ja, wir haben doch alle so einen Freund,
oder, der sowas kennt.
Ja,
es gibt auch irgendwie die Gesellschaft
der Freunde von Pi, glaube ich, und da
muss man irgendwie die ersten 100 Stellen auswendig können
oder so, damit man aufgenommen werden kann.
3,1, 4,2,
wie geht das weiter?
Ja,
3,1, das ist schon ungefähr richtig.
Wie du das sagst, gibt es auch so interessante Fälle, wo dann in irgendeinem CAD-Programm oder so, das ist eine der bösesten logischen Bomben, von denen ich bisher so gehört habe, dass jemand da den Wert von Pi irgendwie subtil verändert hat, so eher sechste, siebte Nachkommastelle oder sowas. Und dann waren halt alle Baupläne irgendwie der letzten zehn Jahre alle falsch.
Sehr schön, sehr schön.
Kann man 3,142 sagen oder ist das auch immer falsch?
3,1415 ist so die Standardweise,
aber es ist eigentlich falsch,
weil es geht ja mit 9 weiter.
Wenn man Pi, ich glaube, auf 15 Stellen genau hat,
dann reicht das schon für alle physikalischen Sachen aus,
weil das dann irgendwie schon im Nanometer-Bereich ist
und so genau kannst du halt nicht mehr.
Und 3,142 ist zu grob noch für sowas?
Ja, da hast du halt, wenn du einen Kreis machst,
der 10 Meter im Durchmesser hat,
hast du halt eine Abweichung von 1%.
Also das ist dann schon eine ganze Menge.
Jede Programmiersprache hat eine konstante eingebaut,
die Pi heißt, Python übrigens auch, math.py.
Und die hat mehr Stellen,
als man je in seinem Leben brauchen wird.
Deshalb völlig ausreichend.
Du hast gerade einen Bogen zu Python gesagt,
ich bin begeistert.
Ja, wunderbar, oder?
Ja, sollten wir vielleicht irgendwie mal zurückkommen.
Das ist mir wieder so völlig unvorhergesehen,
aber ich finde das eigentlich ganz interessant.
Das sollte doch heute eine Basics-Episode sein, oder?
Ja.
Da bist du die Leute halt durch.
Wenn man an die Möhre ran will,
muss man auch ab und zu mal, keine Ahnung.
Man muss ja erst ausgraben, die Möhre.
Ja, rotten.
Gibt es noch
was an News?
Ich weiß nicht genau, ist irgendwas Interessantes passiert?
Django ist
jetzt gerade die
Prerelease-Kandidat.
4.0 ist der Prerelease.
Das hatten wir gewünscht.
Letztes Mal hatten wir Alpha.
Ansonsten weiß ich nicht, gibt es eigentlich nichts.
Python 3.10 ist immer noch aktuell und immer noch
cool. Ja, meine letzte Folge hieß Python 3.10,
Johanna. Ja, gut.
Dann ist es trotzdem, ich wiederhole mich,
es ist immer noch aktuell und immer noch cool.
Ja.
Ja.
Es gab ganz lette Artikel.
Einmal so über Python
im Bankenumfeld gab es einen, der
Oh, Bank-Python, großartig.
Wie, was?
Es gibt wohl eine Variante von Python,
die bei großen amerikanischen Banken eingesetzt wird
und die hat gewisse spannende Eigenschaften,
sagen wir mal so.
Wie heißt die?
Die wird beschrieben als ein Fork des kompletten Bank-Python.
Bank-Python, jetzt habe ich es auch nicht verstanden.
Bank-Python.
Ja, okay.
Großartig.
Ich habe diesen Artikel gelesen und ich fand den super.
Ja, ich auch.
Und da sind auch so ein paar Ideen drin,
wo ich mir denke, ja,
da könnte man versuchen, sich eine Scheibe abzuschneiden.
An Oral History of Bank Python.
Genau.
K.L. Peterson.
Und es sind
auch ganz viele Sachen drin, wo man sich denkt, naja, gut,
okay, gut, die sind halt in dem Jahr, in dem sie
den Fork gemacht haben, stehen geblieben und das war
vermutlich 1994 und
das ist jetzt halt so.
Aber es gibt
auch ein paar Sachen, die eigentlich sehr cool sind.
Also dieser globale State und dieses globale
Deployment und der Code ist
in der Datenbank und du kannst alles anfassen
und Barbara
sind schon viele Dinge, die man sich
mal überlegen könnte.
Ja, Jochen, den hast du vermutlich
in meinen Weaknotes gefunden, oder? Ja, genau.
Ein bisschen Werbung machen für eine eigene Sache.
Ja, richtig, genau.
Ja, ich
hänge mit meinen Weaknotes wieder total hinterher.
Ich muss da unbedingt was machen, aber ich habe irgendwie keine Zeit.
Das ist schrecklich.
Das muss Teil des Prozesses werden.
Das muss eine Gewohnheit werden.
Hast du hier nichts zu tun, Johannes?
Ich habe genügend zu tun,
aber ich habe immer noch
genügend Freizeit, dass ich Reddit
lesen kann. Und wenn ich statt Reddit Weaknotes
schreibe, dann ist das doch ein Gewinn für uns alle.
Ja, das stimmt.
Ja, so viel Freizeit habe ich leider nicht.
Warte mal,
haben wir nicht erst Montagabend
von 20 bis 24 Uhr Computerspiele
gespielt? Ist das Freizeit?
Nein, das ist
Socializing. Und das war erst um 20
oder 36 haben wir angefangen.
Oh, ja gut, okay, dann.
Ja, und dass wir lange gespielt haben,
hat mich natürlich nächsten Morgen
noch was gekostet, das ist ja auch klar.
Wir haben übrigens gespielt
Max, Mechanized Assault
and Exploration.
Das ist ein Spiel, das kam das
erste Mal, ich will jetzt nicht lügen, aber 1998 raus.
Und so sieht's
auch aus.
Es ist trotzdem super, es gibt eine
Max R, das ist eine
Charakter-Version, wenn man die Original
Anführungszeichen, Original-Videos
und Sprites und sowas noch hat.
Sieht gar nicht so schlecht aus, finde ich.
Naja.
Das Interface, also das ist oft so.
Diese alten Sachen haben oft
gute Ideen, aber schlechte Interfaces.
Und ein passiertes RTS mit unheimlicher Komplexität.
Das ist aus der 96 schon, ehrlich.
So alt. Fast so alt wie ich.
Ja, wir haben es geliebt.
Ja, und wir spielen das auch übrigens noch weiter,
die nächste Johannes.
Ich dachte, wir spielen noch andere alte Spiele.
Ja, das werden wir auch mal schaffen, vielleicht nächstes Jahr.
Na gut.
Wie war das gleich noch mit Python?
Ja, genau. Dann machen wir jetzt
Python-Dictionaries und so, ne?
Ja.
Ihr wolltet heute über Dictionaries sprechen.
Ja. Richtig. Verstanden.
Was ist denn ein Python-Dictionary? Ein Wörterbuch?
Ein Mapping von
Dingen auf andere Dinge? Dominik, wie verstehst du
denn ein Python-Dictionary? Also ich meine, der Jochen und ich,
wir können uns gleich noch über die Interna
unterhalten und da gibt es viele spannende Dinge, die man da
besprechen kann. Aber Dominik, wie siehst
du denn ein Python-Dictionary? Was ist denn für dich ein Python-Dictionary?
Was ist denn das, was ein Python-Dictionary ausmacht?
verweifelte, geklammertes, definiertes
Objekt in Python, also dass es kein Z ist, sondern
dass es eine Zuordnung immer macht von einem
Key auf einen Wert und wo
halt der Lookup, also das, wenn man nachgucken kann,
sehr, sehr schnell geht, weil man schön drauf zugreifen kann
und dann gibt es direkt einen Wert zurück,
den es rausschmeißt. Das ist so, dass wie im Python-Dict
man ihn einfach, glaube ich, schnell benutzt.
Okay, Zuordnung
von einem Key zu einem Wert. Das heißt,
ich könnte mir jetzt zum Beispiel zum
Key Dominic deine Telefonnummer speichern.
Ja, und dann könntest du das
Phone Numbers nennen oder sowas und dann
machst du das gleich mit Jochen noch und ja. Und könnte ich mir aber nicht
auch deine Adresse dazu merken?
Ja, aber zu was?
Also ist ja die Frage, wie du das strukturieren
möchtest. Also da kann man ja
beliebige Objekte als Value hinterlegen.
Nee, das stimmt nicht. Achso, als Value schon,
aber Key als Key nicht. Nein, aber genau,
als Value hinterlegen, das heißt, da kannst du natürlich dann... Aber immer nur
einen, oder?
Value, du kannst ja einen Tupel reinpacken.
Okay, ich kann einen Tupel reinpacken, aber ich könnte mir jetzt nicht
zweimal zu dir zwei verschiedene
Sachen merken. Also das müsste ich dann selber machen.
Nee, tatsächlich. Also ein Key muss
das ist unique in einem Gespräch.
Weil das ist ja
in einem Wörterbuch nicht so. Und in einem
Telefonbuch ist das auch nicht so.
Das ist
so eine Sache, die immer, ich mache gelegentlich
Python-Schulungen, übrigens im Dezember wieder.
Naja, aber wahrscheinlich ist dann so, dass dann, wenn du das Lookup machst
und dann Dominik nachguckst und dann gibt es verschiedene Dominiks,
dann hast du erst eine Liste von Dominiks, die du zurückkriegst
und in dieser Liste stehen dann die einzelnen.
Ja, aber ich kriege ja keine Liste.
Wenn Dominik nachguckt, dann kriege ich nur einen Wert zurück.
Der kann dann eine Liste sein.
Genau, aber wenn es eine Liste ist, ja, aber dann, also der Unterschied zum Telefonbuch ist ja der Marginal, du musst halt einfach nur gucken, es ist ein oder mehrere Werte und dann jeweils dann wieder weiterpacken, aber.
Ja, also ich finde, es ist für das Verständnis her schon ein sehr wichtiger Unterschied. In Dictionary kann jeder Eintrag nur einmal vorkommen, jeder Key kann nur einmal vorkommen.
Okay, also ich habe tatsächlich irgendwann nochmal.
In meinem Telefonbuch gibt es sehr viele verschiedene Müllers.
Ja gut, aber wenn du Müller, dann die Liste von allen Müllers bekommst, dann ist ja der Zugriff auf einen einzelnen Müller genau, dann müsste es eigentlich nur eine Ebene tiefer sein, egal.
was ich da so tiefer drin verstanden habe, ist, dass du irgendwie halt
in den Speicher gemeldet wirst und das deswegen so schnell ist,
weil er dann einfach dann die Speicheradresse
nachschauen kann. Ja, das ist ja
die Magie des Hashtables.
Das Hashtable, das müssen wir auch gleich nochmal erklären, was ein Hashtable ist.
Ja.
Was können denn Keys sein? Weißt du das, Dominik?
Weißt du das auswendig? Das ist total spannend.
Wenn ich den Jochen frage,
da weiß ich, dass der das weiß.
Ja, also ich weiß, dass Strings es sein können,
ich weiß, dass es Duples sein können, ich weiß, dass es
Integers sein können.
Noch was?
Strings auch?
Ja, genau, Strings, habe ich ja gesagt.
Kann es auch ein Dictionary sein?
Nee.
Doch, sind die hashable?
Und eine Liste?
Sind die hashable?
Das war schon eine sehr, sehr gute Frage.
Oh, die hashable.
Das frage ich dich, Dominik.
Das weiß ich nicht.
Die Regel ist tatsächlich ganz interessant.
Ein Key von einem Dictionary muss etwas sein,
was sich nicht verändern kann.
Hashable sind diese Typen alle,
aber der Hash kann sich verändern,
wenn sich das Objekt verändert.
Und deshalb gibt es für Liste gibt es Tupel.
Ich kann eine Liste nicht als Key verwenden,
weil die sich verändern kann.
Ich kann aber ein Tupel verwenden.
Und ein Tupel ist ja im Wesentlichen nichts anderes
als eine Liste, die sich nicht verändern kann.
Für Dictionaries und für Sets
gibt es einen äquivalenten Datentyp,
der heißt
FrozenDict und FrozenSet
und das sind im Wesentlichen
Dictionaries und Sets, die sich nicht
verändern können. Das heißt,
wenn ich ein Set als
Key in einem Dictionary haben möchte, muss ich ein FrozenSet
draus machen.
Und das ist auch so ein bisschen
der einzige Sinn für diese beiden Datentypen,
dass du eben ein unveränderliches Dictionary
oder ein unveränderliches Set haben kannst,
um sie als Key in einem Dictionary zu verwenden.
Und warum das machen wir, ist, weil man Lookup haben will
nach dem Motto, wenn das da drin ist, dann gib mir dies.
Ja, oder halt auch, wenn man sie wieder in ein Set packen möchte,
weil man möchte, dass da Schnittmengen von Sachen bilden können
oder feststellen können, ob man das schon mal gesehen hat oder so.
Ja, oder die Reihenfolge spielt keine Rolle.
Das ist ja, das ist so ein bisschen, als Mathematiker,
das Set ist wie eine Liste ohne Reihenfolge.
Oh, die interessante Reihenfolge müssen wir uns auch merken,
weil Order tickt und sowas, weil das ja früher nicht so ging.
das, glaube ich, default ist. Ja, muss man inzwischen nicht mehr.
Früher musste man sich OrderDict immer merken,
aber inzwischen sind alle Dicts OrderDicts, deshalb
den Typ OrderDict gibt's noch,
aber der macht irgendwie gar nichts mehr. Ja, doch, doch, doch.
Der hat noch einen Reversed, aber das ist alles.
Ja, doch, der hat die Verhalten sich unterschiedlich.
Also, tatsächlich
macht das durchaus Sinn. Also, man muss einfach mal,
das ist vielleicht so ein bisschen, vielleicht sollte man das nicht müssen, aber
je nachdem, wie man
Dict verhält, äh, wie man,
wie sich das Dict verhalten soll,
dass man verwendet, also wenn man zum Beispiel viele
Insatz hat von Keys,
dann ist es besser, Order dick zu nehmen
statt dem Default-Ding.
Also es gibt da tatsächlich subtile
Unterschiede. Warum, Jochen? Wie wächst das denn? Wie wächst denn ein Dictionary?
Ja, genau.
Ich habe es vorhin nachgeguckt.
Soll ich es euch verraten?
Ja, verrat mal.
Ein Dictionary fängt an mit null Buckets.
Wenn du ein leeres Dictionary hast, das ist tatsächlich
speziell. Das hat null Buckets, verbraucht
64 Byte.
Das ist übrigens unterschiedlich zwischen 32 und 64
Bit. Maschinen, aber
Ich glaube, wir sind alle inzwischen auf 64-Bit angelangt.
Sobald ich eins einfüge, hat es acht Buckets.
Buckets sind Speicherplätze, erklären wir gleich noch,
weil es eben zu dieser Hashmap gehört.
Und dann verdoppelt es sich jedes Mal, wenn es zwei Drittel voll ist.
Der Speicherbereich wird vorreserviert für alles, was wir reinhaben.
Genau, diese Datenstruktur, die heißt Hashmap
und die braucht leeren Platz, die kann nicht 100% voll sein.
Und deshalb machen die halt immer
eine Verdopplung. Verdopplung ist so eine
Wachstumsstrategie, die gut funktioniert. Auch bei
Resizable-Listen,
die verdoppeln sich
auch. Das ist einfach so eine Wachstumsstrategie,
die so eine gute Balance ist.
Am besten wäre es, glaube ich, wenn man
Wurzel 3 hätte als Wachstumsfaktor. Das ist
2,3 oder irgendwas. Aber dann
hast du die ganze Zeit krumme Zahlen und das ist auch nicht gut.
Ja, stimmt. Das ist bei
dem Array-Modul
bei dem eingebauten.
das habe ich mir mal näher angeguckt
aus Gründen und
da ist das auch so, weil das
ist ja auch interessant, das ist ja
quasi sozusagen wie eine Liste, bloß halt
statisch getübt.
Und man verbraucht tatsächlich
nur den Platz, also für den Integer braucht man halt nur
je nachdem, 32 oder 64 Bit.
Und da ist es auch so,
da kann man Append sagen hinten
und wenn man da was hinzufügt und
der Bereich der Memory View innen
drin ist erschöpft,
dann verdoppelt sich das halt auch immer.
Ja, ist eine klassische Strategie. Okay, das bedeutet aber halt auch, man darf sich nicht darüber im Unklaren sein, so ein Dickjournal verbraucht relativ viel Speicherplatz. Wenn ich einen Eintrag in ein Dickjournal reintue, dann hat es direkt 240 Byte Hauptspeicher verbraucht. Das ist nicht ganz ohne. Wenn ich sechs Einträge reintue, hat es direkt 480 Byte verbraucht. Also es verbraucht relativ viel Speicherplatz.
Es geht hier nicht um Effizienz, sondern es geht um Schnelligkeit. Und diese Schnelligkeit, die hat der Dominik schon angesprochen, das ist sehr schnell. Das heißt, es ist O von 1. Jeder Zugriff dauert immer gleich lang, amortisiert über die Verdopplungen.
Weil wenn ich nämlich ein Dictionary habe, was sehr viele Einträge hat und das verdoppelt sich dann, dann muss dieses Dictionary angepasst werden und eventuell verschoben werden. Dann kann es schon sein, dass es eine Weile dauert, aber amortisiert ist es offeneins jeder Zugriff. Das heißt, jeder Zugriff dauert im Schnitt gleich schnell.
Also amortisiert bedeutet für Dictionary ist der gleichen Länge.
Nee, das bedeutet im Schnitt.
Im Schnitt amortisiert.
Im Durchschnitt bedeutet das, jeder Zugriff braucht ungefähr gleich lang und das ist eine konstante Zahl.
Es gibt einzelne, die dauern ein bisschen länger.
Ich habe diesen Worttransfer von amortisiert auf dem Schnitt hinbekommen.
Wenn du eine große Anzahl Zugriffe machst,
dann ist die Dauer so, als ob du eine Instante gewählt hättest.
Genau, weil das Umbauen quasi Grenzwert Null hat.
Das Umbauen passiert selten genug.
Genau, dass es Grenzwert Null hat.
Deswegen wird amortisiert.
Okay, also O von 1. Also O von 1 bedeutet, es ist kein Problem.
Genau, O von 1. Wir schreiben O von 1. Also wenn ich ein Element einfüge, dann dauert es O von 1. Und wenn ich ein Element rauslese, dauert es auch O von 1. Und beim Lesen ist es immer O von 1. Also das ist nicht nur amortisiertes O von 1, sondern das ist O von 1.
Also das heißt tatsächlich, um nochmal allen Hörern das so ein bisschen näher zu bringen, dieser Zeitnotation Big O noch nicht so viel anfangen kann. O von 1 bedeutet, es dauert quasi keine Zeit, das zu tun.
Doch, es dauert immer gleich lang.
Es ändert sich nicht mit der Menge, also normalerweise, wenn du jetzt sagen, O von 1 im Vergleich zu O von N, ist jetzt, bedeutet das sozusagen, wenn deine Eingabedatenmenge halt nicht N ist, dann, wenn du eine Hash-Map hast, dann ist es halt immer noch O von, ist immer noch konstant, aber bei was anderem, bei einer Liste ist es halt O von N, wenn du darauf zugreifen willst, weil du musst ja alle Dinger angucken, ob es das jetzt ist, was du haben wolltest oder nicht.
Aber OVN1 bedeutet halt, ich kann halt nichts machen. Also das ist halt so und das ändert halt, genau, das heißt also auch egal ob kleine oder große Datenmengen, völlig wurscht, was da passiert und das heißt, der Schritt ist quasi in meiner Berechnung, ob ich da irgendwas Algorithmus verbessern kann, zu vernachlässigen, weil das keine Rolle spielt, ob das, das muss halt einfach so.
Ja, genau.
Und das ist was ganz Witziges.
Ich hatte mal in der Python-Schulung einen Teilnehmer,
der da auch gut mitgemacht hat.
Und der war empört darüber.
Das ist unmöglich, das kann gar nicht gehen.
Das kann gar nicht sein.
Und dann haben wir tatsächlich einen kleinen Benchmark geschrieben
und haben das einfach mal ausprobiert.
Und das ist eine sehr schöne Übung.
Das ist eine sehr schöne Sache, einfach mal auszuprobieren,
wie sich diese Laufzeiten verhalten.
Wie lange es dauert, 1.000 Einträge einzufügen
und 10.000 Einträge einzufügen und 100.000
Einträge einzufügen und die dann auch wieder rauszulesen
im Vergleich zu
einer Liste.
Also du hast einfach quasi die Keys
mit Brackets
dann gesetzt in einer Schleife oder was?
Genau, und habe einfach die
Zahlen von 1.000 bis 10.000 als Key
und als Value, das spielt ja keine Rolle, wenn wir nur die
Größe wissen wollen, das ist dann ein sehr
unnützes Dictionary, weil das halt einfach
immer sagt, zum Key 1 gehört der Wert
1 und
zum Key 10 gehört der Wert 10
Aber wenn es nur ums Benchmarken geht,
dann ist das eine einfache Sache.
Und bei einer Liste genauso.
Einfach mal eine Liste aus zwei Tupeln zusammengebaut.
Und dann in dieser Liste einen bestimmten Eintrag suchen.
Ist halt O von N,
weil durch diese Liste von vorne bis hinten durchgegangen werden muss.
Und wenn ich jetzt den Eintrag 100 suche,
dann muss ich halt das erste Element angucken und fragen,
ist das 1? Nein.
Und das zweite Element, ist das 1? Nein.
Und das muss ich dann 99 Mal machen.
beim 100. sage ich, ist das Element 100?
Und dann sage ich ja und dann bin ich fertig.
Bei einem Dictionary,
Hashmap, wir sprechen gleich, wie das funktioniert.
Im Moment Magie.
Dann passieren
halt 10 Rechenschritte und dann
steht da, okay, du hast jetzt so 100,
hast du dir 100 gemerkt. Und das
spielt keine Rolle, ob das Dictionary einen
Eintrag hat, nämlich nur diese 100, oder
ob es eine Million Einträge hat, das ist immer
gleich schnell. Genau, aber was jetzt da
interessant ist, das hat zwei Dinge. Also erstens,
wie man dann, das ist eigentlich falter Datentyp,
bei wem man dann in der Liste das vielleicht schneller
suchen könnte, weil also theoretisch könntest du ja
in der Liste quasi auch daraus eine Hashtable
bauen, irgendwie aus allen Einträgen dieser Liste und einfach
dann nachgucken, wenn die Hashtable sind,
diese Datentypen oder sowas, ja, genau.
Und dann halt überlegen sich irgendwie den Algorithmus, wie man
relativ schnell die Dinge in dieser Liste findet,
ohne dass man halt über die ganze Liste
iterieren muss. Ja, aber da brauchst du eine andere
Datenstruktur, wenn du nur die Liste hast, dann musst du halt...
Genau, aber ja, genau. Die Liste an sich garantiert dir das
nicht, die garantiert dir nur, das sind Elemente in einer
Abfolge. Die nächste Frage wäre jetzt, wie halt
in der Stickt, was ja auch im Prinzip
eine Liste von Keys ist, jetzt erstmal so
in der Syntag, wie das dann in den Speicher
so reinkommt, dass man diesen Lookup machen
kann, dass man halt quasi
aus dem Wert des Keys
eine Speicheradresse bekommt, quasi.
Indem man da halt reinschreitet.
Ich möchte noch dazu sagen, du hast jetzt gesagt,
das ist eine Liste von Keys,
das ist so, dem stimme ich so nicht
ganz zu. Es gibt nämlich da drei
Ansichten drauf. Es gibt die Keys,
das ist ein Set,
das ist eine Menge, die hat auch keine
Reihenfolge.
Ja, schon, aber früher nicht.
Also hat eine Reihenfolge?
Ja, aber es ist ein Set, weil im Sinne von die Reihenfolge ist nicht …
Die Reihenfolge, die reingeschrieben worden sind?
Ja, das ist die Reihenfolge, die jetzt halt irgendwann dazukommen sind.
Aber wenn wir ein Dict von Python 3.4 nehmen, dann hat das keine Reihenfolge.
Also in Python 3.5 kam ein Order Dict.
Nee, also ein Audit-Stick gab es schon immer, aber dass das sortiert ist, das kam in 3.6 dazu, wurde aber noch nicht garantiert und ab 3.7 ist es halt auch garantiert, dass es so bleibt.
Also in 3.6 war es ein Implementierungsdetail und in 3.7 gehört es zur Spezifikation.
Aber wenn man sich so ein ursprüngliches Dikt mal anschaut,
dann sind die Keys eigentlich ein Set.
Die haben keine Reihenfolge in dem Sinne
und die können auch keine Duplikate enthalten.
Und das ist genau das, was eine Menge ausmacht, ja, ein Set.
Also quasi ein Set of Sorted Set.
Ja, wobei die Sortierung die Reihenfolge des Einfügens ist.
Dann gibt es die Values.
Das ist auch ein View auf diese Daten,
die in dem Diktionary drin sind.
Das sind halt die Werte, die da gespeichert sind.
Das ist im Wesentlichen eine Liste.
Die Liste der Werte.
Und dann gibt es noch die Items.
Das ist eine Menge aus Tupeln,
die jeweils Key und Value enthalten.
Und für mich sind die Items so ein bisschen das,
was das Dictionary ausmacht.
Das ist das, was da drin ist.
Also damit kann man ja quasi auch
über so ein Dictionary iterieren oder sowas.
Man kann das als Methode dot notated aufrufen
und dann kannst du quasi
for key value in dot items, bla.
Genau, for key value in dict items.
Das ist so ein Muster, das sieht man ganz häufig,
weil man da einfach durch das gesamte Dictionary durchgeht.
Man könnte auch sagen for key in Dictionary
und dann sich jeweils den Value holen,
weil es ist ja O von 1.
Das kostet ja so gesehen algorithmisch nichts.
Naja, sag mal so, wenn du eine Vorschleife machst über alle,
dann ist das halt schon O von N sozusagen.
Ja, genau.
Nur im Einzelfall halt nicht.
Aber die Value noch mal rauszuholen, wenn du die schon hast.
Genau, also die O-Notation von for key value in dict items
irgendwas tun und for key in dictionary
und dann den Value als dict von key holen, ist identisch.
Aber die Laufzeiteigenschaften sind natürlich
für den zweiten Fall schlechter,
weil ich dann jedes Mal noch mal in das Dictionary rein muss.
Natürlich nur für einen konstanten Faktor.
Ja, aber der summiert sich halt auch auf.
aber konstante Faktoren, ja, konstante Faktoren
sind halt, also wenn
etwas nur zehnmal langsamer ist,
das ist auch ein konstanter Faktor, das
macht schon
einen Unterschied. Ist schon ein Unterschied, ja.
Ja.
Genau.
Wie kann man denn Dicks bauen, wisst ihr das?
Ich habe vorhin einen ganz coolen Trick gelernt.
Es gibt ja mehrere Wege,
Dictionaries zu bauen.
Ja, was meinte du?
Syntaxmäßig, jetzt geschreibt in der Kamera, oder
wie ich ein Dictionary erzeuge?
Also du kannst es natürlich einmal machen als Dictionary Comprehension,
indem du sagst, geschweige ich in der Klammer,
Key, Value,
oder du machst halt einfach
die Definition einfach in den eckigen Klammern,
schreibst dann den Key und die Value hinterher, oder du
schreibst eine Liste von
Keys und Values mit Gleichzeichen
dahinter und machst dann ein Dict raus,
also Dict of. Ja genau, das ist
der normale, also das ist der
Konstruktoransatz. Ja.
Du kannst die Keys auch in der Schleife
einfach hinzufügen.
Du kannst auch irgendwie, keine Ahnung,
Tupel-Unpacking oder sowas, die ganzen
direkt da rein geben, mit so
Sternchen, Sternchen halt, Quarks und Tacks.
Beziehungsweise, wenn du eine Sequenz
von Tupeln reingibst, von zwei Tupeln, dann nimmt der
die automatisch. Eine Methode, die ich gerne verwende,
ist dict.fromKeys.
Das ist auch
sehr nett. Was macht das?
Naja, du gibst
halt eine Liste von
Keys und dann halt
vielleicht einen Default-Wert oder so und dann
erzeugt er das Ding dann raus mit diesem
Factory-Methoden-Aufruf
von dem Dict.
Default-Dict gibt es noch irgendwie?
Das ist eine andere Sache.
Müssen wir nachher noch drüber sprechen.
Das ist nämlich auch eine spannende Sache.
Ich möchte noch einmal kurz zu der Comprehension zurückkehren,
weil die ist nämlich was sehr, sehr, sehr Cooles.
Und die ist was, was auch für Leute,
die das nicht kennen, super schwer zu verstehen
ist.
Diese
Dictionary-Comprehension ist eine der
coolsten Wege, die es gibt, so ein
Dictionary zu bauen, weil es halt im Wesentlichen
diese Schleife, die man dazu
braucht, in das Dictionary reintut.
Also in die Konstruktion.
Und das
ist was sehr, sehr Mächtiges.
Die Syntax davon jetzt hier im Podcast zu besprechen,
ist vielleicht schwierig.
Muss man sich ansehen.
Aber das ist auf jeden Fall was, was man ansehen kann.
Ich habe vorhin noch einen sehr coolen Trick gelernt und das ist
DictSip. Also wenn ich
eine Liste von Keys habe und eine Liste von
Values,
dann kann ich die sippen und dann
einen Dick Schnee draus machen.
Das geht auch nur für gleich lange Listen, ne?
SIP nimmt auch
unterschiedlich lange Listen und schneidet dann halt den Rest ab.
Aber das ist, glaube ich, nicht der Sinn der Sache.
Der Sinn der Sache ist, du hast schon die Keys und du hast schon
die Values, aber in zwei Händen und mit SIP
kannst du sie in
eine schöne Reihenfolge bringen, die das Dick Schnee...
Einmal Reißverschluss, bitte.
So, wie kann man denn
da Sachen wieder rauskriegen? Dominik, weißt du,
ich frage dich jetzt ab, ich finde das total gut.
Wie komme ich an die Werte wieder dran?
Ja, du kannst einfach
Wenn ich jetzt ein Telefonbuch habe,
wie kriege ich deine Telefonnummer raus?
Du machst halt zum Beispiel entweder ein Get oder halt mit der
Brackets-Syntax ziehst du die Key direkt raus.
Was ist da der Unterschied?
Bei Get kriegst du einen Default-Wert zurück und du kriegst
einen Error, wenn du
daraus einen versuchst, eine Key zu lesen, die es nicht gibt.
Genau, wenn du es mit eckigen Klammern machst,
kriegst du im besten Fall einen Key-Error.
Der heißt tatsächlich Key-Error.
Also wenn man das abfangen möchte,
gibt es das heißt. Genau, also beim Get kannst du halt
dann den Default dann dranhängen. Es gibt noch
zwei andere coole. Ich wollte die Frage beantworten.
Es gibt noch zwei andere coole Attribute, die heißen
Pop und Pop Item.
Ja.
Und die sind quasi
destruktiv, sie sind destruktiver Zugriff.
Wenn ich sage, wie aus einer Liste
wird der Key entfernt. Dominik?
Ja. Dann heißt es
entferne den Eintrag für Dominik,
aber gib mir den Wert auch noch zurück.
Wie bei einer Liste. Wie bei einer Liste,
genau. Also, ja gut, halt mit diesem Key
Zugriff. Bei POP muss ich immer den
Key sagen, bei einer Liste müsste ich den Index
sagen. Genau, also
er gibt dir den ersten Wert, was natürlich beim
DIC nicht geht, weil das nur einer ist. Genau, das heißt
DIC.POP muss immer einen Key haben.
Es gibt da keinen ersten
oder letzten oder wie auch immer.
Aber es gibt POP-Item.
Und POP-Item
das
macht LIFO,
Last In, First Out. Das heißt, es gibt dir
tatsächlich den letzten Eintrag,
der hinzugefügt wurde,
zurück als Item mit Key und Value.
Dann braucht man den Key nicht mehr. Das ist natürlich interessant.
Als Key und Value. Das ist schon
sehr cool. Das heißt,
du kannst so eine While-Schleife machen
und kannst dieses Dictionary sozusagen
abarbeiten.
Und hast dann so eine Art Dictionary-Key. Und das ist
eine praktische Sache,
die ich erst heute gelesen habe.
Ja, sehr schön. Ne, habe ich auch so noch
nicht verwendet, aber da fallen mir auch direkt viele
Sachen zu ein, die man damit cool machen kann.
Ja.
Wo man so ein Dictionary zerlegen kann.
Und ja, es gibt auch noch SetDefault. Ich weiß nicht, ob man das Leuten überhaupt erzählen sollte, dass es die Methode noch gibt.
Nein, das darf man nicht sagen.
Das darf man nicht sagen. Die ist eigentlich nicht gut.
Also die liefert halt auch quasi das zurück, aber mit einem Default, den man dann noch angeben kann, wenn das nicht existiert.
Ja, stimmt. Wo ich anfange, das zu erklären, fällt mir schon ein, dass es vielleicht keine gute Idee ist.
Es ist, glaube ich, besser, da direkt ein Default-Tick zu verwenden.
Genau, das ist auch die Empfehlung. Sollte man halt
heutzutage eher Default-Dict nehmen. Oder Get.
Ein Get und dann den Wert setzen.
Wo ist da ein Unterschied zwischen Get und Wertsetzen
und Default-Dict?
Dafür müssen wir erst wissen, was ein Default-Dict ist.
Dann erzähl mir, was ein Default-Dict ist.
Ein Default-Dict ist ein Dictionary.
Eine Unterklasse von Dictionary.
Das keine Keys hat, aber wenn du einen Key abrufen
willst, den es noch nicht gibt, dann gib dir den Default-Wert zurück.
Genau. Du sagst eben,
welchen Standardwert es haben soll und wenn du
einen Key abrufst, den es noch nicht gibt, kriegst du den Standardwert.
Und da gibt es
drei große Varianten
davon. Die erste ist die Lambda-Variante,
wo du halt eine Funktion
reingibst, die dann diesen Standardwert
erzeugt.
Und das ist sozusagen die allgemeine. Das ist
Default-Dict. Du musst dem Default-Dict irgendeine
sogenannte Factory geben, damit er diesen Wert
erzeugen kann. Und da kannst du jede
beliebige Funktion reintun. Meistens ist das halt irgendeine
kleine Lernversion. Aber es gibt schon
zwei Funktionen, die du da verwenden kannst, nämlich List
und Int,
die nützlich sind. Also wenn du
Default-Dict, Klammer auf, List,
Klammer zu machst, dann heißt
es, das ist ein Dictionary und wenn du da einen Key
abrufst, dann
gibt er dir, wenn du noch nichts eingefügt hast
für diesen Key, eine leere Liste zurück.
Eine neue leere Liste.
Und genauso
für Int. Wenn du
ein Default-Dict
Int hast, dann kannst du
jeden beliebigen Key abrufen und kriegst 0
zurück.
Ja.
Du kannst einen Counter machen, dass der immer geht auf das.
Ja, aber Counter gibt es auch.
Da gibt es schon eine Klasse für, ja.
Und die ist richtig cool, diese Counter-Klasse.
Die müssen wir uns auch gleich noch besprechen.
Okay, wofür würde ich Default-Dict verwenden?
Das klassische Beispiel ist, wenn man sich so einen Counter baut.
Aber nochmal, wenn du das gleiche nochmal aufrufst,
dann gibt man natürlich den neuen Wert zurück, ne?
Genau, also wenn du einen Wert in dieses Default-Dict reinspeicherst,
dann ist es wie ein normales Dictionary, ja?
Also wenn es diesen Key schon gibt,
dann kriegst du das, was da gespeichert wurde.
Das kann auch was anderes sein als ein Int oder eine Liste, ja?
Das heißt, es ist nicht eine Typisierung,
sondern das ist nur so dieser Fallback.
Da ist nochmal noch eine
Zwischenfrage, ein kleiner Express. Wenn ich jetzt da
ein Get mache auf so eine Liste, ja, auf so ein Default-Dict
von der Liste und ich habe dann
eine leere Liste in der Hand und ich schreibe in die was
rein, beim nächsten Mal auf
denselben Key gibt der mir dann diese Liste,
in der was drin ist?
Nee.
Warum nicht? Das wäre das, was Jochen
vorher gesagt hat, das wäre SetDefault.
Weil du beim Abrufen
entweder den Wert kriegst,
der in dem Dictionary drin ist,
oder den, den die Factory erzeugt.
Aber der wird nicht automatisch in dieses Dictionary abgelegt.
Aber das ist doch bei Listen, haben wir doch das Problem,
dass dann das Objekt der Liste dann es doch schon gibt
und dass das Objekt dieser Liste, auf das dann ja ...
Genau, aber die wird nicht in das Dictionary abgelegt.
Du kriegst dann eine neue Liste, die du nur in der Hand hast.
Und du musst die dann tatsächlich zugreifen.
Wenn du das möchtest, dass du eine Liste abrufst
und die dann bearbeiten kannst, dann musst du SetDefault machen.
Und SetDefault heißt, ruf einen Key ab, wenn es den schon gibt,
gib mir das, was da drin ist, ansonsten setze
in dem Dictionary den Wert, den ich dir
da als Default angebe und
gib ihn mir zurück. Okay, ja, das
dachte ich, dass wäre das, was Default-Dictionary machen würde, okay,
das heißt, dafür muss ich Set-Default machen.
Genau, dafür musst du das Set-Default machen.
Ja, aber es ist, die Funktion
ist Set-Default, also sie ist in mehrerer
Hinsicht verwirrend, sie ist auch verwirrend benannt,
wie man es auch gerade wieder sehen konnte
und vielleicht sollte man das echt mehr, weil
tatsächlich, wenn man so eine Default-Dict macht, ist es sauberer
und ja, genau,
was ich noch anmerken wollte zu den
Factory-Funktionen, die man übergeben muss. Also es kann
eine beliebige Funktion sein. Die einzige Bedingung ist,
sie darf keine Argumente
nehmen.
Wenn man jetzt so mehrfach verschachtelte
Geschichten baut, das geht.
Aber das wird dann auch relativ schnell relativ
unübersichtlich.
Ich habe noch keine gute Lösung
dafür, aber das ist, dann muss man halt
da, das sieht dann komisch aus, aber ja.
Das ist ein bisschen blöd, wenn es keine Argumente sein können.
Also Factory-Story
würde man ja gerne mal auf eine bestimmte Art und Weise
initialisieren. Ja, das muss man ja
irgendwie von einer, die Falltrack irgendwie alles
schon erben und muss das dann irgendwie schon hinstecken.
Ja, aber da gibt es etwas,
also zumal, wenn man jetzt
bei unterschiedlichen Keys unterschiedliche Sachen
machen möchte, es kann ja manchmal sein,
du sagst so, wenn ich diesen Key habe, okay,
dann möchte ich ja gar keine Liste dazu machen, sondern was
ganz anderes oder so.
Und dann geht das mit dem Default-Tick ja alles
so nicht mehr so richtig, eben deswegen, weil man kann
halt nicht ein Argument angeben,
was man dann, also das ist,
das geht dann nicht mehr. Da gibt es aber auch etwas
sehr cool ist, was ich auch erst in der Vorbereitung, ich habe ja
einfach nochmal geguckt, was zu
dieser Episode, habe ich mir nochmal so ein bisschen
angeguckt, was habe ich denn an Literatur zu Dicts
steht da irgendwas Interessantes drin und habe ich tatsächlich
etwas gefunden, was ich noch nicht wusste, wo ich auch sagen
würde, oh cool, dass ich das jetzt weiß und zwar
gibt es Dunder Missing
als sozusagen Spezial
Methode, die man überschreiten kann,
wo man dann den Key bekommt.
Das ist quasi der Key Error. Du kannst den Key Error
überschreiben. Ja.
Mach dann Default Dict, mache ich dann eine neue Klasse, die von
DefaultDictErben, du beschreibst dann dann Missing und guck
dann mit einem MatchCaseStatement, was
da drin ist. Genau, oder
du kannst von DefaultDictErben,
na klar, aber das musst du dann ja
im Grunde nicht mehr, weil wenn du die Methode überschreibst,
dann bestimmst du ja selber, was passiert.
Und da kannst du alles. Das ging
früher übrigens auch nicht.
Konnte früher nicht von DictErben, deshalb gibt es noch eine Klasse, die
UserDict heißt.
Das heißt tatsächlich, ich mache tatsächlich so was
ähnliches wie UserDict und ich mache eine neue Klasse auf die
Erb einfach von Dict und da überschreibe ich dann nur die
Misting-Methode und dann gucke ich halt, was das ist, statt dem
Key-Error jetzt rauszugeben, dass er dann tatsächlich
irgendwas Neues anstellt.
Das würde auch tatsächlich funktionieren, aber
es wird,
diese Diskussion hatten wir in dem
Python User Group Düsseldorf
Channel auch vor kurzem,
ob es denn okay ist, von Dict zu erben
oder wenn man lieber von UserDict erben soll oder so
und ich hatte das halt noch so im Hinterkopf,
dass man von UserDict erben soll und nicht von Dict
und tatsächlich
habe ich jetzt auch nochmal nachgeguckt
und nee, man soll von UserDict erben
und nicht von Dict. Also man kann das ja
zwar jetzt, aber... Was ist da der
Unterschied? Also der entscheidende
Unterschied, warum das unter Umständen
einem Probleme machen kann, ist,
dass
bestimmte Methoden
halt, also Missing ist jetzt, die
funktioniert, die kann man überschreiben, aber bestimmte andere
nicht. Und wenn du dann Dict auf bestimmte
andere Arten, wenn du da Sachen mit
machst, dann geht das
an den Methoden, die du überschrieben hast, vorbei.
Das heißt, wenn du von Dict
von dem Build-in diktierst
und dann überschreibst du halt
irgendeine Methode und denkst, ja, müsste doch funktionieren,
dann funktioniert es manchmal halt vielleicht nicht, weil
zum Beispiel, also auch der Konstruktor
davon ist halt so, der schreibt das halt
irgendwie direkt, der geht nicht über die
Set-Item, Get-Item-Geschichten,
die es da halt normalerweise geht. Das heißt,
dann verhält sich das Ding unter Umständen
unerwartet und ja, Laufzeitverhalten
ist auch so ein bisschen anders, also
und, ja, das habe ich jetzt aber auch
wieder vergessen, also es war auch irgendwie, ist eine
wichtige Geschichte, warum das, wenn das
im Data-Attribut ist und sozusagen die
Zugriffe dahin nur delegiert werden,
das macht auch irgendwie, ich glaube, es kann sogar sein, dass
das der Grund ist, weshalb man Set-Item, Get-Item
dann überhaupt quasi richtig überschreiben
kann, weil wenn das halt
delegiert wird. Ja, genau, genau.
Ja, und daher
sollte man, wenn man das selber,
wenn man erben will und will Sachen überschreiben,
dann lieber UserDict nehmen, statt
einfach vom Build-In erben. Also
UserDict ist quasi
eine Klasse, die das gleiche Interface hat
wie Dictionary. Ja.
aber eben ein Attribut
heißt, das heißt Data
und das ist ein Dictionary und
einfach alles durchreicht an dieses Data.
Genau. Und das bedeutet, dass wenn
ich von UserDict ableite, kann ich jede beliebige
Methode überschreiben und die wird dann auch
korrekt aufgerufen, auch Konstruktor und alles mögliche.
Ja, genau.
Ja.
Ja, okay, wusste ich auch nicht. Ich wusste nicht,
dass es da Unterschiede gibt. Ja, es ist immer wieder interessant, auch wenn
ich dachte, also ich meine, das verwendet man ja jeden Tag
und irgendwie schon ganz lange und so und
dann ist es so, kann ja eigentlich nichts Neues mehr.
Aber manchmal so, ja.
Aber das ist was, was man doch relativ selten macht von Dictionary.
Also generell von
Build-ins, so Sachen,
fühlt sich immer so ein bisschen komisch an.
Ja, ist nicht so häufig.
Die sind einfach gut genug.
Beziehungsweise, wenn man
eine neue Datastruktur sich schreibt,
dann benutzt man normalerweise eben eine
und leidet nicht direkt
davon ab. So ist meine Erfahrung.
Instanziert die dann irgendwie so mit so einem
Injektor-Pattern oder sowas, dass man die halt dann benutzt.
Genau, dieses Data, dass da halt
sagst, okay, mein Baum ist
eigentlich eine Liste, aber
ich habe
eine Liste, die das macht. Ich habe nicht das Interface
von Liste geerbt, sondern ich habe halt eine
in der Hand, die das macht.
Das ist so meine Erfahrung. Ich weiß nicht, wie ihr das seht.
Doch, doch. Nee, ich sehe das
ganz genauso.
Achso, genau, das ist auch noch der eine
Grund dafür, warum
das mit dem Delegieren eine gute Idee
ist, weil halt ansonsten, wenn du direkt erbst,
dann hat
dein Objekt eine ganze Menge Methoden,
die halt unsinnig
sind unter Umständen. Also
in einem Kontext, wo man sich dann fragt, wenn man so
Dia macht auf dein Objekt.
Und dann sieht man halt einen ganzen Haufen komisches
Zeug, wo man sich dann so, hä, warum ist das denn alles da drin?
Was man halt einfach so mitbekommt,
wenn man das, wenn man da direkt erbt.
Also, ja.
Okay, ich frage mich alles.
Das ist dieses Interesse.
Wir müssen noch so ein paar Sachen, ich habe jetzt meine Notizenliste,
die ist leider gerade leer gegangen, aber
da ist so ein
Ladegerät und da ist so ein,
das kannst du dein Telefon anschließen.
Oh, du hast USB-C? Wow.
Als Apple-Haushalt USB-C.
Ja, ja, brauchen wir das schon?
Cool. Es gibt eine Methode
in Dictionary, wo wir gerade über das
Dictionary-Interface sprechen,
die ist in 3.9 dazugekommen.
In 3.9 hat sich das Dictionary-Interface
verändert. Okay.
Und zwar ist der Pipe-Operator
dazugekommen. Ah, ja, richtig.
Ja, klar, natürlich.
Und das ist sowas, was,
wenn man das braucht, dann ist das
ungeheuer wichtig und wenn man es nicht
braucht, dann ist es so, okay.
Nie gedacht, dass jemand sowas brauchen könnte.
Das ist Dictionary-Vereinigung.
Ja, Unions zwischen von Dicts.
Genau, da gibt es jetzt den Operator dafür.
Früher musste man immer,
jede von uns hat so eine Sammlung von Tricks,
wie man Dictionaries vereinigt.
Ja, das ist ganz einfach mit Stern, Stern
und unter Dictionary und
ja, und das
gibt es jetzt als Operator und auch mit
Pipe gleich, also man kann auch gleich rein
vereinigen, wobei das einfach ein Update
ist, meiner Meinung nach, oder?
Oh, das würde ich jetzt ausprobieren,
das weiß ich auch nicht, aber es stimmt, ich
ich wusste, dass das passiert ist, ich habe es aber nie
verwendet seitdem, daher ist es
mir jetzt gar nicht mehr bewusst, dass es diese Erinnerung gab.
Ein Update ist ja Union,
ist es exklusiv, ist die Frage.
Es ist immer exklusiv,
weil du ja keine Keys verdoppelt hast.
Ja, aber dann geht das nicht mehr im Update, weil bei Update werden ja nur die Keys
geupdatet, die in dem Update enthalten sind.
Nee, die .update,
dictionary.update übernimmt
alle Keys und Values aus dem
Herangebiet. Genau, aber die, die es noch nicht drin waren.
Genau, aber wenn welche vorher schon drin waren
und die dann überschrieben werden.
Dann werden die überschrieben.
Genau, aber wenn die vorher schon drin wären,
die nicht.
Das ist bei Vereinigung aber genauso.
Nein, aber wenn die vorher schon drin waren
und nicht in dem neuen drin sind,
dann sind die, wie sie vorher waren.
Aber wenn du den Union Operator gleich machst,
dann sind sie eben nicht mehr drin,
weil sie halt nicht in dem Update sind.
Das verstehe ich jetzt nicht.
Okay, du hast zwei einigermaßen disziplinierte Names.
Du hast zwei Mengen, du hast D1 und D2.
Genau, du hast zwei einigermaßen disziplinierte Names.
Und da sind irgendwie zwei Keys gleich.
Wenn du jetzt mit dem Update machst,
werden die zwei gleichen Keys
in dem ersten Dictionary überschrieben.
erstes Addict-Update
wenn du aber die Union machst
erstes Addict-Union, zweites
nein, dann sind nur noch die zwei Keys drin
nee, das kann ich
nee, das wäre ja der Schnitt
nicht die Vereinigung
achso, stimmt
das gibt es nur bei Set
das gibt es nur bei Set
bei Set gibt es das
gibt es nicht auch
die Intersect
nee, für Addict-Union gibt es keine Intersect
Okay, schade eigentlich, weil das wäre doch eigentlich sehr logisch, dass das mit dem, jetzt habe ich den Pipe Operator nicht richtig verstanden.
Es wäre logisch, dass es diese ganzen mathematischen Operationen alle für Set und Dictionary haben.
Genau, dass du halt quasi dann nicht nur sagst, du machst halt einfach irgendwie ein Und-Und oder wie auch immer man das machen will von dem anderen Dikt und dann hast du die Unions direkt, das wäre doch schön Syntax, oder?
Ich probiere das gerade mal in der Rappel aus, ja.
Ja, mach mal.
Union ist oder und das
ist einfach
die Vereinigung. Also die Keys
aus dem einen Dictionary und die Keys aus dem anderen Dictionary.
Ja, okay. Mit den Werten aus den jeweils
letzten. Mach mal und und, Peter.
Nee, das geht, nee, und und geht schon mal gar nicht.
Und und gibt es in Python sowieso nicht? Gibt es nicht.
Und und geht nicht. Und da sagt er
unsupported operant type.
Bitwise geht auch nicht. Ja, okay.
Also tatsächlich, es geht nur die Vereinigung, ja.
Ja, okay, dann ist das gleich wie ein Update.
Wohingegen bei set, wenn man das jetzt so macht,
Bei Set gibt's Intersect. Es gibt
Set.Intersect, es gibt
Set.Union und es gibt Set.
Es gibt noch eine dritte.
Difference. Symmetric
Difference oder sowas. Ja, genau.
Ja, Symmetric Difference ist ja
das eine minus das andere plus das andere minus das
eine.
Schade, dass der Intersect nicht hat. Warum hat der das denn nicht?
Also bei Set geht, aber bei Dix nicht.
Das müsste ja irgendwann mal reinkommen.
Die Frage ist, wie sollen denn dann die Values aussehen?
Bei der Intersection
der Keys. Welche nimmst du denn dann?
Hm, jetzt hast du mich.
Eine Liste von beiden wahrscheinlich oder sowas.
Ja, aber das wäre dann schon sehr unerwartet, oder?
Ich meine, man könnte auch auf die Idee kommen,
es müsste anders sein und dann wundert man sich halt,
was passiert, was, also, ja.
Ja, also eigentlich müsstest du den Schnitt über die Keys machen
und dann entscheiden, aus welcher Quelle du die Value nimmst.
Das ist halt quasi wie beim Update mit Exclude oder sowas.
Kann man das machen mit Exclude?
Nee.
Ja, auch doof.
Ja, also, was mir jetzt
wieder anfällt, es ist irgendwie relativ ähnlich zu dem, was man
irgendwie bei den neuen Sachen hat, wie mit Data Classes
oder PyIdentic oder sowas, oder
was gibt's denn noch, alles AdWords oder sowas?
Also, was diese, ja,
oh, es gibt auch noch, ja,
Named Tuples zum Beispiel.
Genau, das ist auch spannend.
Warum denn Named Tuple?
Ja, das ist ein total komischer
Name dafür, ist auch, ich weiß
auch nicht. Um dotnotated Zugriffe
auf irgendwelche Objekte zu haben für die einzelnen.
Okay, aber dann, also was ist denn der Unterschied zwischen dem Dictionary und einer Klasse? Weil bei einer Klasse habe ich auch Namen drin, Punkt irgendwas und da ist genau ein Wert dazu drin.
Du hast einen Konstruktor und irgendwie noch.
Ja gut, aber das ist ja, da musst du ja eigentlich.
Der Konstruktor ist nur eine Konvention.
Ja, du kannst auch deine Sachen anders konstruieren, genau. Also ich würde sagen, es gibt keinen großen Unterschied. Tatsächlich ist es eine sehr ähnliche Geschichte und ich glaube, ich meine, es ist ja auch so, dass.
Alles Diktat.
Genau, also in Python-Objekte, das sind halt Dicts sozusagen, was ihre Struktur angeht.
Mit ein kleines bisschen Syntax dazu.
Genau.
Tatsächlich ist es sogar, also ich weiß nicht, ob das bekannt ist.
Unter uns dreien sicherlich, aber unter den Hörern vielleicht nicht.
Jede Instanz einer Klasse ist im Wesentlichen ein Dictionary.
Also das hat ein Attribut, das heißt unterstrich, unterstrich, Dict, unterstrich, unterstrich.
Und da stehen die Dinge drin, die
die Values in dieser Instanz
sind. Also eine Instanz ist immer
ein Dictionary in Python.
Das ist irgendwie
komisch oder seltsam.
Gerade wenn man von anderen Programmiersprachen
kommt, weil in anderen Programmiersprachen ist es ja nicht so.
Weiß ich nicht. Also ich würde
gerade sagen, bei dem, was üblicherweise
so als Skriptsprache
qualifiziert wird.
Da ist das auch, also bei
JavaScript, da heißen die Dinger sogar Object.
Vielleicht ist das das entscheidende Merkmal
einer Skriptsprache.
Also bei
Perl war das auf jeden Fall auch so.
Da waren auch, also ich meine, das hat ja
keine offizielle... Bei dynamischen
Klassen und dynamischen Instanzen geht es ja quasi
nicht anders. Du musst ja quasi diese Zuordnung haben
von Attributname zu irgendeinem
Wert. Ja.
Genau. Aber bei kompilierten Sprachen ist das ja anders.
Ne, da ist es anders, genau. Bei kompilierten Sprachen
musst du es nur während der Kompilierungszeit machen
und dann kannst du sagen, okay, das Attribut
mit dem Namen x ist halt Feld Nummer 2.
Ja. Man kann das
in Python auch machen, quasi. Man kann das
halt festdengeln, ohne dass das halt dann
noch so dynamisch...
Ja, man kann halt die Attribute
in einem Spezialattribut
dann da Slots angeben und dann
sind die halt da fix.
Die kann man dann aber auch nicht mehr dynamisch zuweisen.
Ist dann aber...
Das ist aber auch nur Konvention, oder?
Nee, nee, das ist dann tatsächlich schneller.
Wenn ich so ein Slot-Ding mache, dann kann ich doch
trotzdem zusätzlich...
Achso, Moment.
Kann ich dann trotzdem dynamisch zuweisen?
Ich weiß es nicht, meine, das geht dann nicht mehr.
Da muss ich ausprobieren.
Doch, er macht seinen Editor an.
Einer von uns beiden ist gleich falsch.
Oder eben Name-Tupel.
Name-Tupel ist genauso,
nur halt schneller.
Weil der eben diesen Aufruf
nicht über ein Dictionary macht, sondern über eine lineare
Liste, weil die Annahme ist, dass du
nicht so viele davon hast.
Oder vielleicht ist das so eine Hybrid-Sache.
So ein bisschen ist das Dictionary ja der Kern
von Python. Es gibt ja so eine
Liste. Moment, ich habe es gerade ausprobiert.
Nein, wenn man halt Slots
definiert hat und dann was anderes dynamisch
zuweisen möchte, kriegt man eine Exception Attribute Error.
Also wenn man Slots macht,
dann ist es kein richtiges Dictionary, sondern nur.
Also es ist halt auch so ein Trick, damit kann man
halt, wenn man viele Objekte hat oder so, damit kann man
die Objekte selber schneller machen und sie brauchen viel weniger
Speicher. Jetzt muss man noch
erklären. Aber Nentupel macht das doch genauso,
oder Jochen? Jetzt ist es auch schneller als
eine allgemeine Klasse.
Ja, ja, klar. Named Tuple macht das genauso und darüber funktioniert es. Ich glaube, dann intern kann es sogar sein, dass die interne Datenstruktur Tuple ist und sich dann sozusagen nur eine Zuordnung gemerkt wird von Index auf irgendeinen Namen.
Aber das würde ja schon nichts bringen, dann hättest du ja den gleichen Aufruf wieder, sondern das muss eine andere Struktur sein, das ist keine Hashmap.
Ja, ja, ja, nee, das ist irgendwas anderes, keine Ahnung, ja, was auch immer.
man darf nicht vergessen, wenn ich eine kleine Menge
an Keys
habe, dann ist
so eine Art Listenzuweisung, also ich merke mir
einfach, die Keys in
einer Liste und gehe die Liste linear durch,
das kann schneller sein als so ein
Hashmap-Zugriff. Ja. Für kleine
Werte von n.
Für kleine Werte von n ist o von n kleiner
als o von 1. Kann sein. Ja, kann
gut sein, ja. Und das ist, glaube ich,
der Trick von Slots und der Trick von Name-Tupel,
dass die halt sagen, okay, wir machen
keine allgemeine Zuweisung, sondern wir sagen,
aha, wir haben ja nur drei
benannte Attribute, dann ist es besser, die in einer Liste
zu haben.
Okay, das Slots bitte noch einmal
explizit erklären, weil das kommt gerade zum ersten Mal vor.
Slots und Name-Tupel.
Also Slots, wie gesagt,
darüber weiß ich jetzt gar nicht,
was du diktst, frage ich.
Erklär es mal als Name-Tupel.
Was ist denn ein Name-Tupel?
Ich wollte gerade nach Slots fragen.
Ja, das kommt gleich.
Naja, da definierst du
sozusagen ein Objekt, dadurch, dass du am Anfang
du gibst halt so, glaube ich, wie das Aufruf
Name-Truppel, dann sagt man irgendwie
einen Namen dafür und dann sagt man die
Attribute, die das haben kann
irgendwie und dann. Und das
verhält sich dann aber wie eine Klasse. Ja, genau.
Und dann kann man mit Punkt drauf zugreifen.
Aber nur mit diesen, die ich da angegeben habe.
Also wenn ich ein Name-Truppel habe, das heißt
FUBA.
Keine Ahnung, das heißt FUBA und das hat die Attribute
A, B und C.
Dann kann ich ein FUBA.A
machen und fuba.b und fuba.c und kriegt
die entsprechenden, das verhält sich dann wie
ein Dictionary, ja, für diese drei Keys.
Aber Dict kann ich ja nicht mit Dot machen,
muss ja mit den Key-Ketten. Genau, genau, also das ist
wie eine Klasse, wie eine Instanz von einer Klasse.
Also das ist so ein
Ding, das mache ich häufig, ja, dass ich einfach eine Klasse
mache, die heißt Data-Holder
und die hat keine Attribute, weil dann kann ich
nämlich mit Punkt irgendwas. Wenn wir jetzt gerade schon bei
Named Tuples noch sind, da gibt es übrigens auch noch eine kleine Neuerung,
weil früher gab es ja immer vom Collections Named Tuple,
man musste Named Tuple off machen und jetzt gibt es aber auch
Typing Named Tuple und Typing Named Tuple ist
ein bisschen eleganter, weil dann kannst du einfach das wie eine Klasse
schreiben und dann darunter
die Attribute. Ich würde Name-Tupel gar nicht
so prominent, weil
auch das ist, glaube ich, nicht mehr
so wirklich empfohlen und nicht mehr
so richtig aktuell. Das gibt es halt noch.
Aber eigentlich,
was man... Dann erklär doch mal Slots.
Wie auch immer. Wenn man Name-Tupel
verstanden hat, dann ist Slots leicht zu erklären, weil
Slots ist nämlich eine andere Syntax
für die gleiche Funktionalität.
Ja, du sagst,
welche Attribute eine Klasse
haben darf und dann hat es nur genau diese
Attribute. Das heißt, okay, also in Slots ist eine
Dann-Dann-Methode, die in einer Klasse drinstehen kann.
Nicht eine Methode, nein, nein, das ist ein Attribut.
Das ist ein Attribut, ah, okay, das ist ein Attribut.
Dann gibt es eine Liste von Namen rein. Und das ist eine Liste
ist und in der Liste stehen quasi
die Strings drin von den
Namen, die als Attribut
einer Klasse, die als Methode oder Attribut
erlaubt sind. In unserem Beispiel von eben wäre dann die
Klasse, die Klasse hieße Fuba
und die hätte ein Attribut, das hieße Dann-Dann-Slots
und da steht drin A, B und C
als Strings. Stehen da auch
Methodennamen drin oder nur
Attributnamen? Ne, nur die Attributnamen.
Und wenn ich da Methodennamen reinschreibe,
dann kann ich da eine Methode für definieren, die trotzdem funktioniert?
Kannst du machen, klar.
Wenn du willst. Da müsste man ja ausprobieren, was da passiert kann.
Das kann komische Sachen passieren.
Ne, das kannst du generell machen. Du kannst generell
an jede Klasseninstanz eine Methode
dran machen, die muss halt den Parameter
self haben als erstes
und dann funktioniert das wie eine Methode, weil
Methoden an Klassen sind nichts anderes als
Funktionen, die den Parameter
selbst haben. Aber was ist denn, wenn das nicht in den Slots
drinsteht? Ja, wenn es nicht in den
Slots drinsteht, kannst du nicht drauf zugreifen. Genau,
das heißt, die Methode kann ich nicht aufrufen, weil es nicht in den Slots
drinsteht. Das heißt, auch die Slots sind für Methoden
dann exklusiv. Du kannst die Methode in die
Klassendefinition reinschreiben und
die kommt dann zusätzlich zu den Slots dazu.
Du kannst sie halt nicht dynamisch
hinzufügen. Du kannst sie nicht dynamisch hinzufügen.
Slots wird zusammengebaut aus dem, was in dem
Attribut Slots drinsteht und in den Namen, die
die Methode entdeckt. Da wäre ich mir nicht so sicher.
Probier es mal aus, Jochen.
Das ist meiner Meinung nach so.
Jetzt müssen wir gerade ein bisschen tippen.
Okay, ich habe es jetzt gerade gleich.
Okay.
Ich habe es gleich.
Also foo.astf.
Das funktioniert schon mal.
Also genau so.
Und jetzt sagen wir foo.slots.
Ich glaube nicht, dass das zusammengebaut wird.
Ich glaube, dass Slots bleibt so, wie es ist.
Aber das funktioniert.
Methoden gehen, ohne dass es in Slots drin steht.
Und es ist nicht in Slots drin.
Du kannst über Methoden hinzuschauen.
Genau.
Weil die Methoden an dem Typ dranhängen
und nicht in der Instanz.
Okay.
Das heißt, an einer Instanz, die ein Slots-Attribut hat,
kannst du nichts verändern.
Du hast nur genau diese Keys, die da drin sind.
In dem darüber liegenden Typ hast du Methoden drin.
Und da kannst du auch, kannst du alles Mögliche drin haben.
Das ist deine normale Klasse.
Okay, es geht also nur für die Instanz, die Slots.
Genau.
Die Slots sind für Instanzen von dieser Klasse.
Und wenn diese Klasse aber selbst noch Methoden hat oder Attribute,
Du kannst auch in diese Klasse ein Antiboot reinschreiben.
Du kannst da x gleich 10 reinschreiben.
Und das kannst du auch auslesen.
Und du kannst es auch an der Klasse verändern.
Aber nicht in den Instanzen.
Weil in den Instanzen darfst du nur auf Slots zugreifen.
Und das bedeutet,
dass eine Klasse mit Slots
im Wesentlichen wie ein Name-Tupel ist.
Nur besser. Mit besserer Syntax.
Und mehr Methoden.
Und das ist auch der Grund, warum Name-Tupel nicht mehr so richtig...
Jawohl, aber ich finde, dass das neue Name-Tupel
von Apple Typing ist doch gar nicht so schlecht.
Ne, also es hat auch noch andere Nachteile.
Also es gibt ja jetzt
auch denn etwas, was man vielleicht
eher nehmen, also vielleicht meinst du das auch,
es gibt ja Dataclasses, die sind ja auch jetzt in der
Sprache drin, direkt.
Und die sind auch in eigentlichen, also es gab es auch
ich weiß nicht, Artikel zu,
ich meine, ich habe es jetzt nur mal so gelesen, ich habe es nicht wirklich
selber überprüft, aber so wo Leute sagen, also bitte
nehmt doch alle Dataclasses und nicht mehr nehmt Tuppel,
weil Dataclasses, es ist schneller, es ist besser,
es ist in jeder Hinsicht besser, es gibt keinen Grund mehr
das zu nehmen, das alte Zeug ist nur noch drin.
Man kann es lesen.
Okay, ja.
Es kann mehr und
es ist schneller. Also ich meine, es gibt
keine großen Nachteile.
Und
es gibt das natürlich, also
das Vorbild für Dataclass
ist halt dieses Adress-
Modul, das sehr beliebt ist. Das kann halt dann noch
viel mehr. Und es ist auch
relativ schnell, wenn ich das so richtig verstehe. Das ist auch sehr nett,
ja. Und
also das ist das, was vielleicht
damit angefangen hat. Dann Dataclass ist eingebaut
und jetzt gibt es halt auch noch sowas wie Pydentic,
Das ist ja auch so ähnlich. Das ist noch schneller.
Der Münster bei Dataclass.
Das ist nicht schneller als Etos.
Ich weiß nicht. Ne, Pidentic, meine ich auch, ist eine eigene Geschichte.
Ja, Pidentic ist eigen, aber es ist nicht schneller.
Doch, doch. Ne, es ist nicht.
Ne. Es ist ein Einstehen sogar langsamer
als Etos zum Beispiel. Okay.
Jochen dachte, es wäre schneller. Ich dachte, es wäre Dataclass.
Ja, gut.
Ich habe irgendwo so ein Video,
das muss ich eigentlich mal in den Show-Notes verlinken,
wo jemand das ganz gut auseinandernimmt, wo der so
Timings dafür macht. Also, das muss sich mal irgendjemand
mal ganz genau angucken und dann Bescheid sagen,
wie das denn wirklich ist.
Ja, also in dieser Episode hier in den Podcast
kommen und uns das allen erklären, wie es ist.
Genau, das wäre gut.
Ja, absolut.
Genau, aber es ist auf jeden Fall ein Ding,
was halt, und
diese ganzen Dinge, wenn man
die sich alle anguckt, also Name-Tupel
ist halt das, was man am wenigsten nehmen sollte von den ganzen
Sachen.
Ich finde ja die moderne Sonntag, das sieht eigentlich ganz hübsch aus.
Es ist halt so schnell.
Wenn du es halt aufschreiben willst,
vom Typing-Import Name-Tupel, dann machst du einfach
auf, keine Ahnung, Named Tuple,
Define Named Tuple von irgendwas und dann schreibst du halt
die Attribute untereinander wie in der Klasse,
definierst die und ist klar, welchen Datentyp haben die denn und so,
das sieht schon so aus als... Okay, vielleicht muss ich mir
das auch nochmal angucken, weil dass ich das
vom Typing importiere, kenne ich jetzt noch gar nicht.
Ja, aber das ist auf jeden Fall, glaube ich, ich weiß auch gar nicht,
ob sich eine Implementierung da was geändert hat, aber
ich glaube, so werden wir das eigentlich haben, oder?
Also das musst du jetzt mal kurz aufmachen, um dir das mal
anzuschauen. Okay, dann muss ich
da mal eingehen. Also ich würde tatsächlich
eher Dataclasses verwenden für diesen Newscase,
Aber ich habe ja immer seltsame Ansichten.
Ja, das nächste Neues war anders.
Ich habe mich dann abgefunden, dass ich nicht im Standard bin.
Ach, so sieht das, nee, okay.
Ach doch, so sieht das aus, ja, okay.
Ja, Typing, Punkt, Named, Tuppel und dann sagt man hier irgendwie quasi.
Ja, aber das ist sogar noch, Moment, das muss ich mal so sehen.
Ja, da unten, also das nächste Beispiel ist sogar noch hübscher.
Ihr wisst, dass die Zuhörer den Monitor nicht sehen können.
Genau, das ist das Problem bei Podcasts.
Und das Problem ist auch, ich kann das jetzt nicht vorlesen,
Das kann ich schon, hilft nur nicht.
Ja, genau, aber ich finde so die Sündheit,
das sieht doch gar nicht so schlecht aus.
Ja, okay, also gut.
Das ist halt klasse.
Muss ich das mal jemandem angucken und dann zu Bescheid sagen.
Also es ist auch eine Möglichkeit, die man machen kann.
Ja, ja, ja.
Ja, ja, sehr nett.
Okay, aber das ist ja nur syntaktischer Zucker, oder?
Wenn ich das jetzt richtig verstehe.
Ja, syntaktisch Zucker.
Ja.
Sehr gut.
Also dann ist es quasi ein Name-Tool.
Okay, schön, das ist auch okay.
Es gibt noch zwei Dinge, die ich
vorhin gelernt habe. Das erste ist Counter.
Wir haben es schon kurz angesprochen.
Counter ist auch eine Dictionary-Subklasse
und die
macht im Wesentlichen das, was sie sagt.
Ich gebe eine Sequenz rein
und die zählt, wie oft jedes Element drin vorkommt.
Das heißt, wenn ich einen String
reingebe, dann habe ich hinterher ein Dictionary und in dem
Dictionary steht drin,
wie oft jeder Buchstabe in diesem String
vorkommt.
Und das ist großartig, weil das
baut man sich so oft selbst
und das baut man sich so oft
von Hand und macht
ein Default-Dict oder macht ein Get und
inkrementiert die Zahl dann und so weiter.
Einfach ein Counter und die Sequenz
reintun und fertig. Und man kriegt ein Dictionary
raus mit der Anzahl.
Super, ist großartig. Und das hat auch diese ganzen
Funktionen, die man dazu braucht. Also wenn man das
dann updaten möchte oder wenn man das
wenn man
einen Generator hat oder wenn man
irgendwas anderes in der Hand hat und das nicht
genau vorher weiß oder wenn man zwischendurch noch was machen möchte,
Das ist großartig.
Ein Counter zusammen mit einer Comprehension, super.
Ja, ja.
Das deckt so viele von diesen Fällen ab,
für die man sonst Default-Dict verwendet.
Ja.
Ich habe noch was anderes Schönes gefunden
und zwar heißt es Chain-Map.
Das ist auch im Collections-Modul drin.
Was ist denn eine Chain-Map?
Eine Chain-Map, das ist so ein ...
Mich hat das so ein bisschen an JavaScript-Objects erinnert.
Wenn du nach einem Key suchst,
dann suchst du quasi durch die ganze Reihe durch.
Das heißt, Chainmap nimmt eine Menge von Dictionaries
und wenn du nach einem Key fragst,
dann guckt er im ersten Dictionary, ist der da drin?
Wenn er da drin ist, kriegst du den Wert.
Wenn er nicht drin ist, guckt er im zweiten nach.
Wenn er da drin ist, kriegst du den Wert.
Wenn er nicht drin ist, guckt er im dritten nach und so weiter,
bis er alle seine darunter liegenden Dictionaries durchgeschaut hat.
Wenn er es nirgendwo findet, kriegst du immer noch einen Key Error.
Wenn du aber einen Wert reinschreibst in diese Chain-Map,
dann schreibt er das immer in das oberste Dictionary rein.
Das heißt, du veränderst nur das erste Dictionary aus deiner Kette,
hast aber lesenden Zugriff auf die darunterliegenden.
Und das ist so ein bisschen so, wie Objekte in JavaScript funktionieren,
wie Object in JavaScript funktioniert.
Wenn du liest, liest du immer aus dem Ersten, was verfügbar ist,
aber wenn du schreibst, schreibst du immer ins Oberste rein.
Ja, ja, ja.
Ja, ich überlege gerade auch, also ich meine,
das ist auch sowas, ja, ich weiß es nicht genau,
aber es ist halt eine, ich mache jetzt auch
so ein bisschen JavaScript gerade und
was ich da, was dann
doch ein bisschen einfacher hinzuschreiben ist als
in Python ist halt dieses
Dreipunkt
Spread Operator Syntax, wo man dann halt
sich neue Sachen generiert, indem man halt ein altes Ding nimmt
und dann sagt man Punkt, Punkt, Punkt, altes Ding
und dann schreibt man noch ein neues Ding
dazu oder so und mit Chain Map hat man
ja da quasi was ganz
ähnliches. Genau, das ist eben
wie gesagt diese Prototyp-Sache.
JavaScript ist die halt der Kern
von JavaScript.
Jedes
Object oder jedes Dictionary in JavaScript
hat einen Prototypen, auf den
du zurückfallen kannst.
Und das kannst du hier mit Chainmap nachbauen.
Ja,
nett. Fand ich sehr schön,
dass es gibt. Habe ich noch nie gebraucht.
Wüsste jetzt auch nicht, an welcher Stelle
ich das einsetzen würde, aber
gibt es
auf jeden Fall und ich glaube, wenn man
das braucht, ist das eine sehr, sehr nützliche Sache.
Ja.
Weil man so Hierarchien
damit bauen kann.
Ja.
Vielleicht nochmal einmal ganz kurz, weil ich
gerade nachgeguckt hatte zu diesem
WhichPythonDataClassIsBest, habe ich
ein Artikel, also ein Video gefunden von
einem Kanal, der mCoding heißt
und da vergleicht jemand tatsächlich
Dataclasses, NameTupil,
TupilEthers und Pydentic
nach Geschwindigkeit und Memory
und so. Und da schneidet Pidentic
vor allem beim Erstellen von den Objekten relativ
schlecht ab. Okay, gut, ja.
Das irgendwie
15 Mal so lange dauert oder so.
Aber sonst vielleicht schnell.
Ja, gut.
Im Laufe seines Programmiererlebens
hat man sich davon weg entfernt, auf Geschwindigkeit
zu achten. Notiz hätte er wieder
angemacht. Ja, genau, Geschwindigkeit, ja.
Da ist die Frage, braucht man das überhaupt, will man das?
Genau. Egal, haben wir nicht genug Hauptspeicher
und sind solche, also das war
nie genügend Geschwindigkeit und nie genügend.
Ja, wir hatten letztens
jemand,
den kennt ihr
bestimmt auch, der
Pavel Mayer aus
Chaos Radio
oder
aus dem Chaosumfeld, ne, die kenne ich ja nicht.
Ah, okay, der, naja, gut.
Der hatte das mal
irgendwie so beschrieben, dass ein Computer
eigentlich für ihn nur eine relevante Eigenschaft,
also eine
ein Attribut hat, das
wichtig ist. Oder es gibt
drei ganz wichtige. Und zwar, das ist halt
erstens Performance. Das zweite ist halt
Performance. Und das dritte ist, was auch
noch sehr wichtig ist, Performance.
Sind ja nur drei Dinge.
Ja, da ist auch
schon was dran. Aber tatsächlich
sowas wie Lesbarkeit ist auch nicht
so schlecht. Ist das der Prof. Mayer, der dieses
mega langsame Covid-Dashboard geschrieben hat?
Ja, genau.
Just saying.
Es gibt so Leute, also ich meine
es gibt auch Felder
in denen das wichtig ist, ja
die Geschwindigkeit und Geschwindigkeit ist immer irgendwie
so ein Faktor, der wichtig
ist, aber man kann
da so tief reingehen, wie man
möchte und es gibt immer noch jemanden, der das schneller macht
Ich sehe mir
sehr gerne die Videos von Casey Muratori an
und der kommt halt aus der Spieleentwicklung
und der sagt
man kann in C alles machen, also solltest
du in C auch alles machen, aber wenn es schnell
sein muss, dann musst du halt schon auf die Intrinsics
gehen und den Prozessor kennen, den
du da gerade benutzt und dann
den Befehlssatz
kennen, weil dann kannst du nämlich alles
256 Mal so schnell machen wie vorher
und
ja, das ist
prinzipiell korrekt, aber
Vielleicht ist Assembly-Coden
auch zu langsam, also wenn man es gut kann, ich weiß nicht.
Noch ganz kurz.
Ich kann das sicherlich gut genug, aber
noch kurz zu
genau, da gibt es auch gerade auf Netflix
so eine Miniserie oder so
The Billion Dollar Code, die ist quasi
mehr so, die orientiert sich
an der, an dem oder deren
Biografien da in, ja.
Und die scheint wohl ganz gut.
Wir machen schon wieder Werbung,
Jochen, das ist aber eine werbungsvolle Folge.
Ja, diesmal ist ja noch gar nicht so,
also, ja, gut, wir machen Werbung,
Werbung machen wir immer, aber wir werden
nicht dafür bezahlt, dass
Netflix, falls ihr zuhört,
der Jochen wäre durchaus offen dafür, bezahlt
zu werden. Du weißt, Johannes Verkunde
ist ja nicht mit anderen Werbepartnern direkt parallel.
Also Netflix-Werbung würde ich
vielleicht auch nicht.
Wir hatten ja letztes Mal, also wenn wir jetzt schon das Thema Werbung haben,
wo der jetzt gerade Werbung für so eine Werbung macht.
Ich mach mal eine Chapter Mark hier.
Ja, wir haben ja überlegt, ob wir Werbung
mal schalten sollen und ein bisschen uns drüber lustig gemacht und
wir haben ein bisschen Feedback bekommen. Du wolltest sagen, ja, mach doch
einfach. Ja, dann haben wir jetzt auch gedacht,
ja, okay. Na gut, dann machen wir halt.
So ein bisschen kostendeckend
arbeiten oder so. Gibt es Leute, die euch
bezahlen, das ist ja verrückt.
Noch nicht.
Berührt und schockiert.
Du wirst nicht bezahlt, Johannes.
Achso, ja gut dann.
Dann ist mir egal.
Nicht so direkt, aber ich meine, das wäre natürlich so eine Sache,
die man machen könnte. Man könnte halt also einmal
Hostingkosten und so die anfallen, ein bisschen damit
vielleicht bezahlen.
Aber was man auch machen könnte, wir könnten
dem Johannes ordentliches
Audioequipment schicken zum Beispiel.
Ja, da müssen wir nochmal drüber nachdenken.
Dann ist das jetzt hier mit der Spendenaufruf,
wenn die Zuhörer gerne möchten, dass
ihr mich besser hören könnt, dann
finden sie jetzt eine folgende Bitcoin-Adresse.
Wir schalten ab jetzt einfach Werbung.
Ja.
Aber wenn ihr dann Werbung
schalten würdet und dann auch
Geld einnehmen würdet, dann könntet ihr
euch ja auch richtige Gäste leisten und
dann würde ich ja einfach gar
nicht mehr, ich wäre dann einfach gar nicht mehr hier,
sondern ihr würdet euch richtige, kompetente Gäste
brauchen. Vielleicht könnte man sich dann auch
andere Hosts leisten, die das so
etwas professioneller machen und sowieso
eine andere Webseite, die auch nicht so kacke aussieht
und dann könnten wir endlich, was könnten wir
denn dann eigentlich machen? Ich wollte mir ein Schloss kaufen.
Dann könnten wir uns an den Strand setzen und mal
eure Hobbys verfolgen, vielleicht, keine Ahnung,
vielleicht machen wir einen Podcast auf.
Ja.
Naja.
Ich hab schon gesagt, ich warte immer noch auf mein Schloss.
Ja.
Auch, möchtest du auch?
noch einen Spendenaufruf starten. Also mein Spendenaufruf
war für ein gescheites Mikrofon, Dominik's
Spendenaufruf ist für ein Schloss.
Ja, für mein, nicht für ein Schloss, für mein
Schloss. Ja, ja, für sein Schloss. Ja, okay.
In dieser ganzen,
in diesen ganzen anderthalb Stunden, wo wir jetzt schon
zusammensitzen, haben wir
jetzt tatsächlich noch gar nicht drüber gesprochen, was
eine Hashmap überhaupt ist. Du hast die Stunde vorher vergessen,
wenn wir gebraucht haben, unser Audioequipment vorzubereiten,
obwohl wir alle voll drauf sind. Ja, das ist halt am einen schlechten Mikrofon,
aber
trotzdem sind wir noch nicht so weit gekommen, zu
erklären, was überhaupt eine Hashmap ist und wie sie
funktioniert. Ja, okay. Das stimmt.
Also das ist irgendwas, wo man
ganz schnell nachgucken kann, weil man direkt weiß, wo es ist.
Also man kann quasi dem Key ansehen,
wo er sein muss.
Oder so. Dem Key nicht,
aber man kann aus dem Key was rauskitzeln.
Okay, aber aus diesem Rauskitzeln
weiß man direkt, wo es sein muss, weil
das irgendwie...
Ja, der Trick
ist im Wesentlichen
schon im Namen. Also man nimmt
nicht die Keys selber, sondern man nimmt Hashes von Keys.
Deswegen muss es auch Hatchable sein.
Genau deshalb muss es hashable sein. Und weil eine Eigenschaft eine Hash-Funktion sein soll, dass sie nicht vorhersehbar ist, bedeutet das auch, dass sie gleich verteilt ist über den Raum der möglichen Hash-Ausgänge.
Das bedeutet, wenn ich aus einem Wert einen Hash mache, dann kriege ich im Wesentlichen einen zufälligen Wert in der Menge aller möglichen Hashes raus.
Und wenn ich diesen Hash jetzt
mit Modulo nehme, ja, und quasi
als Index in eine Liste reinnehme,
dann bedeutet
es, dass der irgendwo hinzeigt.
An einen Index, der
nicht vorhersehbar ist und
der auch gleich verteilt ist über die gesamte
Reichweite der Liste. Aber ich muss
da reingehen, quasi die Länge der Liste. Das heißt, ich weiß,
wie groß das maximale Reich ist. Genau, ich muss wissen, wie groß
die Liste ist. Beziehungsweise Python
macht da viele coole Tricks,
die
dir helfen. Magie, Magie.
Aber das ist bei einer Hashmap
immer so, die hat so einen Füllungsgrad,
wir haben es vorhin schon angesprochen, bei Python ist es
2 Drittel, die ist maximal 2 Drittel voll.
Also Wurzel 3, hast du gesagt.
Wurzel 3 wäre noch besser, aber
das ist halt leider kein Integer.
Ist das der goldene Schnitt? Nein.
Ne, der goldene Schnitt
ist 1,618 noch was.
Was ist Wurzel 3?
Der heißt auch Phi.
Wurzel 3 ist
1,7 irgendwas.
Verdammt, knapp daneben.
Vielleicht noch besser.
Ist übrigens auch interessant,
weil ternäre Logik wäre besser,
weil das näher an irgendeiner Zahl dran ist.
Ach, keine Ahnung, spielt keine Rolle jetzt.
Das Wichtige ist,
wenn ich aus einem Diktionario rauslesen möchte,
dann nehme ich den Key, den ich lesen möchte
und hashe den
und nehme dann diesen Hash als Index in eine Liste rein.
Und wenn in dieser Liste an der Stelle was steht,
was nicht None ist,
dann ist das der Wert,
der zu diesem Key gespeichert wurde.
Und umgekehrt, wenn ich in eine Hashmap etwas reinschreiben möchte,
dann mache ich den Hash aus diesem Key
und schreibe den Wert in diese Liste
an der Stelle des Hashindex rein.
Und das ist sozusagen der Trick.
Ich berechne einen, ich nenne es mal,
zufälligen Index in diese Liste
weil der gleich
verteilt ist, weil diese Hash-Funktion gleich verteilt
ist, füllt die diese Liste
gleichmäßig auf und
kann
dann
eben in O von 1, weil diese Berechnung
dieses Hashes immer gleich lange dauert,
diesen zufälligen Index finden und dann
da reinschreiben. Jetzt gibt es ein Problem.
Was ist, wenn zwei Hashes zu dem
auf den gleichen, also wenn zwei Keys auf den
gleichen Hash-Index zeigen?
Und das passiert, wenn wir
Wenn wir ein Dictionary haben, was acht Einträge hat,
dann ist die Wahrscheinlichkeit, dass zwei auf den gleichen Index zeigen,
vergleichsweise hoch.
Eins zu acht.
Das heißt, man muss sich eine Technik überlegen,
um sogenannte Kollisionen zu vermeiden.
Und da gibt es zwei Möglichkeiten.
Entweder kann ich sagen, jeder Eintrag in meinem Dictionary ist eine Liste.
Das heißt, wenn zwei auf die gleiche Sache herrschen,
dann muss ich halt durch diese Liste durchgucken
und da den entsprechenden Wert rausholen.
Das heißt Chaining. Oder man kann einen neuen Hash berechnen und sagen, wenn da eine Kollision ist, dann verändere ich meine Hash-Berechnung und wähle sozusagen einen neuen zufälligen Hash. Und die Wahrscheinlichkeit, dass da eine Kollision auftritt, wird eben jedes Mal kleiner. Und das heißt Open Addressing.
Und Python Dictionaries machen tatsächlich Open Addressing, das heißt, die haben keine Liste an jeder Stelle gespeichert, sondern die sagen halt, wenn da eine Kollision ist, wenn das nicht der richtige Key ist, den ich da gefunden habe, dann muss ich diesen Prozess fortsetzen.
Muss einfach sozusagen nochmal einen Hash berechnen.
Ein Hash vom Hash.
Ja, da wird dann so ein Counter mitlaufen gelassen, damit man eben wieder diese Eigenschaft hat, aber sozusagen diese Bits wiederverwenden kann.
Dass du nicht in zwei Richtungen wächst,
sondern dass deine Hashmap einfach nur in eine Richtung wächst.
Das sind Implementierungsdetails.
Aber das ist im Wesentlichen die Magie,
dass man aus dem Key einen Hash berechnet
und dieser Hash hat eine gewisse Eigenschaft
und die heißt gleich verteilt.
Und auch wenn ich die auf einen Index zusammendampfe,
dann sind sie immer noch gleich verteilt
und das ist der Trick da dran.
Bedeutet halt, dass der Key hashable sein muss.
Es gibt eine ähnliche Datenstruktur, die heißt TreeMap.
Da werden die Keys in einen Tree abgelegt.
Dann müssen sie nicht hashable sein,
dann müssen sie sortierbar sein.
Und dann habe ich halt einen Tree.
Dann habe ich Zugriffe, die alle log-in sind.
Genau.
Ich weiß nicht, ob es immer noch so ist,
die Hash-Map-Default-Implementation
der Standard-C++-Bibliothek von Boost
war irgendwie so ein Tree-Map.
Eine Tree-Map, ja.
Und hat dann irgendwie,
als wenn man was optimieren wollte,
dann ein C++ geschrieben habe und dann war das
überraschend von der Performance her, weil das war dann hinterher
langsamer als die Ticks und Beiden.
Großartig.
In Java gibt es diese
beiden Optionen unter diesen Namen. Es gibt
HashMap und es gibt DreamMap. Das heißt, bei Java
muss man sich immer raussuchen, was man haben möchte.
Die Antwort ist immer HashMap,
aber egal.
Und natürlich bei einer HashMap
heißt das, dass man immer Hash-Funktionen
haben muss. Und Hash-Funktionen sind auch
so eine Sache. Die müssen
schnell sein und trotzdem gut und ich möchte
gerne viele verschiedene haben und
die sollen alle schnell sein und alle
möglichst gut. Und da die
richtige Hash-Funktion rauszufinden
und eine gute Implementation davon zu haben, ist nicht ganz
einfach.
Welche wird verwendet?
Das weiß ich nicht.
Na, ich stelle
dir Fragen, das weiß ich nicht.
Ja, es gibt ja so Hash-Funktionen, die kennt man ja.
Es gibt MD5 und SHA-1
und SHA-256 und
CRC32 und die sind
aber alle nicht geeignet dafür
und dann gibt es so welche, die kennt man
überhaupt nicht und die haben
auch abgefahrene lustige Namen,
von denen ich jetzt keinen einzigen sagen kann, weil ich
kenne sie ja nicht, die aber eben
keine kryptografischen Hashes sind, sondern
eben solche Hash-Funktionen, die man für solche
Satenstrukturen verwendet,
die dann halt aber andere Eigenschaften haben.
Die brauchen dann nur acht Cycles und
geben nur zwei Byte als Hash zurück
oder irgendwie solchen Quatsch,
weil das hier viel, viel wichtiger ist.
Ja, also ich kenne die Hash-Funktion für kleine Integers
und die ist sehr einfach.
Die ist das Integer selber.
Also der Hash von 1 ist 1, der Hash von 2 ist 2.
Aber das wird dann, wenn die Zahlen größer werden,
ist das dann nicht mehr so toll.
Aber das ist der Hash von 128, Jochen.
Das glaube ich auch immer noch, 128.
Ah, ich glaube, es geht nur bis 127.
Ja, ich weiß.
Ich glaube, Small Integer in Python geht nur bis 127.
Moment, Moment, ich habe doch hier die Rappel schon aufgemacht,
da kann ich auch gleich nochmal
128.
Ich habe ja kürzlich
immer noch 128, aber wenn ich
512, verdoppeln
war eine gute Strategie, habt ihr eben gesagt.
512 ist auch immer noch, 512
bei 1024 auch immer noch, oh mein Gott.
65. Vielleicht ist es bei Integers
einfach immer so.
Nein, nein, wenn die wirklich groß werden,
dann ist es nicht mehr so. Okay, sie müssen
wirklich groß werden. Ich bin gerade schon bei einer Million,
bei der Milliarde. Dann sind es vermutlich 32
Bit, wenn die über 32 Bit sind.
Unsigned and, man weiß es nicht,
mal ein Minus.
Es gibt ja ein sehr schönes Paper, das heißt
People mistake knowledge
on the internet for their own knowledge.
Du hast eine gefunden. Also ich habe eine gefunden,
aber da musste ich jetzt schon irgendwie 20, 30 Nullen
hintendran machen. Ich weiß gar nicht mehr, wie das heißt.
Das sind die,
die früher L hießen. Das war super.
Erstmal mal verdoppeln, also
12.420, dann 10.000, 100.000,
1.000.000, 10.000.000, 100.000.000
und dann auf einmal so. Ich weiß nicht, wie die Zahl
heißt, die jetzt da rausgefallen ist, aber ich weiß
jetzt doch, bis wo denn das
wohl ist, das ist wohl tatsächlich bis zur Grenze, bis zur
64-Bit-Grenze, weil das, was hier rausgefallen
ist, ist irgendwie maximal 64-Bit.
Aber wo es halt die Implementation-Details
sind, das ist eigentlich signed oder unsigned in Python
und was ist das in 64 oder in 32?
Das ist signed, meine ich.
In Python
die Integer sind Long-Integer.
Also 64, also
es gab früher eine Unterscheidung zwischen Long-Integer
und Integer, die gibt es halt Python 3 nicht mehr.
Ist jeder Integer eine Ganzzahl
und die verhalten sich auch korrekt wie mathematische
Ganzzahlen. Du kannst beliebig viele Stellen machen.
Die Implementation dahinter
schaltet um zwischen Integers
und Long-Integers. Aber das ist ja nur
ein Implementationsdetail. Das ist nur
ein Umsetzungsdetail.
Hash von minus 1 ist minus...
Hash von minus 1
ist minus 2. Ja, schön.
Interessant. Okay.
Wieder was gelernt. Gut. Die exakte
Funktion spielt gar keine Rolle.
Wenn du Hash von irgendeinem String machst, kriegst du halt auch
irgendeine Zahl raus.
Das Wichtige ist eher, dass das
schnell sein muss und dass es
deterministisch ist und so weiter und diese ganzen
Eigenschaften, die man so stellt an
Funktionen und halt,
dass es gleich verteilt ist über die Menge
der Hashes. Und ich glaube, die Menge der Hashes,
wenn du die Zahlen vor dir hast, Jochen, die sehen aus wie 32
Bits-Zahlen, oder?
Ja.
Minus 2?
Minus 4.
Nein, keine Ahnung.
Oh, hash minus 1 ist gleich hash minus 2.
Da hast du direkt eine Kollision.
Dann musst du Open Addressing machen.
Ja, okay.
Ja, witzig, witzig.
Das heißt, kann man Dicts,
Keys, wenn das Int sein können,
können das auch negative Int sein?
Ja, na klar.
Alles, was Hash-Build ist.
Das heißt, wenn du minus 1 reinschreibst,
dann muss er tatsächlich eine Kollision machen
und minus 2, dann muss er quasi eine Ebene tiefer gehen.
Ja, okay.
Du kannst auch deine eigenen Objekte
ersparen werden. Ja, genau. Das ist auch etwas, was ich gerne
mache, tatsächlich.
Und was Leute mal so überrascht,
wenn man dann Objekte als Keys hat, dann
sagen die immer so,
aber nein, das geht.
Das ist okay. Du solltest dann eigentlich
auch immer noch Frozen-Versionen machen.
Musst du dann eine Methode an deine Klasse dran machen, die
hashable ist? Ja, das muss natürlich hashable
sein. Wie wird das hashable?
Was versucht der beim Hash denn zu machen?
Implementierst einfach Dunder-Hash.
Dann wird die aufgerufen und dann
kannst du, wenn du eine ID schon hast,
dann kannst du die natürlich auch zurückgeben.
Oder du kannst halt, ja,
wie auch immer du das...
Also du gibst etwas zu...
Jedes Objekt ist doch herrschbar, oder?
Die Objektidentität als Herrschfunktion.
Ja, das kann natürlich sein,
dass das der Default ist.
Ja.
Hm, wie könnte man das jetzt schnell rausfinden?
Ha.
Hey, dann mal auf.
Dann dein Hash.
Help, dann dein Hash, wie wäre das denn?
Genau, aber du kannst natürlich
deine eigene Hash
Scheint so zu sein, ja.
Help, dann dein Hash?
Du kannst natürlich deine eigene Funktion
da reinschreiben, das heißt, du kannst
eine Hash-Methode schreiben, die
für deine Objekte spezifisch ist.
Aber wenn du das machst,
wenn man seine eigene Hash-Methode
implementiert, dann muss man wirklich
darauf achten, dass sich
Keys in einem Dictionary nicht ändern dürfen.
Das heißt, wenn ich einem Objekt
eine Hash-Funktion gebe,
eine Hash-Methode gebe,
die sich zwischendurch verändern kann,
dann geht mein Dictionary kaputt.
Ja.
Und das geht dann auch gleich richtig kaputt,
weil dann finde ich gar nichts mehr in meinem Dictionary.
Ja, ja, ja.
Also da muss man dann natürlich aufpassen.
Aber ich meine, oft hat man ja tatsächlich eine ID,
die man nehmen kann.
Und man gibt halt bei der Hash-Methode,
man rechnet das nicht selber aus,
aber man gibt halt etwas zurück, was dann
durch Hash nochmal durchläuft.
Man fällt zurück auf irgendwas, aber dass man
halt sagt, okay, eine Adresse ist halt,
der Hash einer Adresse ist der Hash aus der
Straße und der Postleitzahl und der
Stadt, das ist ja schon
irgendwie naheliegend, dass du halt irgendeinen
wegbildest, was du dann hashst.
Und
klar, das kann man natürlich
machen. In meiner
Erfahrung tritt es nicht so häufig auf, aber wenn
du sagst doch, dass du das gerne machst, dann
Vielleicht mach ich es auch falsch, ich weiß es nicht so genau.
Also ja, gerade mit
Zusammenhang mit Data Classes,
beziehungsweise so Atris, da benutze ich...
Data Classes sind ja automatisch hashable, oder?
Ja, bei Data Classes weiß ich es gar nicht so genau.
Also ich hab das jetzt, das, was ich jetzt im Kopf hab,
ist mit Atris und da muss man dann auch,
da kann man dann auch solche Sachen sagen, also einmal, man kann es natürlich
selber implementieren, aber man kann auch sagen irgendwie,
also ich hab, es soll hashable sein
und diese Attribute will ich dafür
verwenden und die müssen dann auch natürlich auch in der Uni sein
und so, ja.
Und dann macht es manchmal Sinn,
weil dann kann man halt bestimmte Sachen
look-uppen
mit einem anderen bestimmten Ding und dann
ist es manchmal ganz praktisch.
Ja, das ist ja oft so, dass
man seine
Algorithmen beschleunigen kann, wenn man so ein
look-up macht, wenn das
in dem Algorithmus vorkommt.
Wir hatten einmal so einen Fall
im Computerclub, da war der
Bison auch da und hat da eben seinen Algorithmus mit
einer Liste geschrieben, wo er
dann eben immer die Elemente aus der Liste raussuchen
musste, wo er immer nachgucken musste, habe ich diesen
Knoten schon besucht
in der Liste und das war halt O von N
und dann haben wir es umgebaut zu einem Set,
was
im O von 1 ist, wo diese Operation O von 1 ist
und dann wird es halt deutlich schneller. Also wenn man das
braucht, ist das
schon ein Superpower.
Ja.
Hast du noch etwas
auf deiner Liste stehen, Johannes?
Nee, ich habe jetzt tatsächlich meinen ganzen Notizzettel
abgefrühstückt.
Jochen, hast du noch was zu Dikt, was wir
noch nicht gefunden haben? Also ja, was ich ganz
gerne vielleicht noch sagen
wollen würde oder so, ist halt, dass man
auch selber sich Sachen implementieren kann,
die dann halt so funktionieren wie Dicts.
Es gibt ja seit Python 3.3, glaube ich,
Protocols oder was weiß ich wie das.
Man hat halt auf jeden Fall diese AppSecBase-Klasses,
wo es dann Interfaces für diese ganzen Geschichten gibt.
Und da hat man dann halt...
Moment, also Protocols sind fertige
ABCs, AppSecBase-Klasses? Protocols sind was
total Cooles. Die Implementierung
von Python-Modulen,
die es schon gibt? Ach, cool.
Die kann man ja auch fürs Typing dann benutzen.
und so. Ja, genau. Und die sind großartig
fürs Typing. Da kann man nämlich richtig gutes
Duck-Typing machen, was aber trotzdem getypt
ist. Genau. Das ist großartig. Genau. Und dann kannst du
eben deine eigene, für
eben deinen Anwendungsfall etwas Spezielles hinbauen,
wo du dann sicher sein kannst, dass sich das dann aber
genauso verhält und auch an den Stellen
verwendet werden kann, wo du normalerweise
ein DIC benutzen würdest und so.
Da kannst du auch sehr coole Sachen mitmachen.
Wobei das Protokoll von einem DIC-Driver
ist ja vergleichsweise groß. Was ist das denn?
Was ist denn ein DIC-Type? Das ist, meine ich, mappable,
aber ich gucke mal gerade.
wo haben wir das denn da?
Es gibt Mapping, Mapping heißt das, genau.
Ein Mapping.
Mutable Mapping.
So, ach,
jetzt steht das Interface hier aber nicht dabei.
Collections.abc
Import.
Abstract Base Class.
Moment, ich importiere das gerade mal, mach mal ein Diagramm.
Ja, das ist cool, weil dann kannst du einfach von Mapping ärgern lassen
und alles, was du nicht implementiert hast, wird dann einfach direkt
geraced.
Genau. Wenn das halt nicht da ist, das ist doch schon
Beziehungsweise ein MyPi oder ein Type-Checker
sagt dir der auch direkt das.
Ja, aber du wirst direkt gezwungen, das richtig zu implementieren.
ABC Blood Collections.
Ja, ich hab mich gerade geschützt.
Weil ABC ist ja die ABC selber drin.
Ich weiß, ich weiß.
Gleichzeitig reden, tippen und das alles.
Ich glaube, was du auch machen kannst,
wo keiner zu sehen kann.
Mach mal ein neues Objekt von Mapping auf, einfach.
Das kannst du nicht ins Studio.
Sehen Sie nächstes Mal in diesem Podcast.
Das geht nicht.
Genau, da steht aber jetzt dann, was du brauchst.
Ja, okay.
Du musst halt Get-Item-Itter
und Längen definieren von meinem
Wrapping. Okay, zumindest, ja.
Also das Interface selber ist jetzt doch
etwas größer, das sind halt
37
Methoden und das ist natürlich schon eine ganze Menge.
Ja, das hatten wir ja vorhin auch schon angesprochen, dass eben
Dicts relativ viel Oberfläche
haben. Ja.
Weil sie halt für alles verwendet werden.
Ja.
Ja, aber eben, also man kann das
halt verwenden. Interessant,
interessant.
Ja. Ist das euer Lieblingsdatentyp?
Ja, also von den primitiven
Dingen auf jeden Fall. Ich habe das auch
letztens, also diese ganzen
Type-Ins,
Typisierungsgeschichten, die es jetzt neuerdings gibt.
Es gibt ja immer so, auf Twitter gibt es dann so
die alten Säcke, die da rumhängen
und die
äußern sich ja manchmal.
Wie alt bist du gleich noch, ihr jungen Hüpfer?
Ja, sie sind noch älter als ich.
Die im Kopf alten Säcke.
Ja, nee, also
verdiente Veteranen.
Ah ja, okay, sehr schön.
Der Python-Community und
die sich manchmal so ein bisschen despektierlich äußern,
was diese ganzen neuen
Entwicklungen angeht. Der ganze Scheiß, gar nicht mehr
Pythonic. Genau, und so ein bisschen
kann ich das natürlich auch, kann ich das nachvollziehen, muss ich
sagen. Also zum Beispiel, ich sag jetzt mal
einen Namen, David Beasley zum Beispiel.
Der ganz viel cooles
Zeug gemacht hat, der auch eines der besten Bücher
Python-Bücher geschrieben hat, irgendwie Python
Essential Reference, glaube ich.
War lange super. Jetzt gibt's da sogar
Python Distilled, ist jetzt nochmal
eine neue Ausgabe.
Super Buch.
Und der sagt so, also ich weiß
nicht, dieses ganze Typing-Zeugs,
ich finde, das sieht nicht gut aus,
ich mag das nicht. Und was wir
früher, als wir nix hatten, was wir gemacht haben,
wir haben immer irgendwie Dicts genommen und
ein paar List Comprehensions und damit haben wir
alles gemacht. Alles haben wir damit gemacht. Und das war
viel besser, als irgendwie, wenn einer sich mit Java
hingesetzt hat und hat dann irgendwie so angefangen
erst mal Interfaces zu definieren und dann
irgendwie, keine Ahnung, sich da erst mal
in, ja,
weiß ich nicht, in so ein Spinnennetz
aus komischen Dingen, die man alle so machen
muss, weil man sie halt machen muss.
Wenn man irgendwas hinschreibt, genau,
diese ganze Zeugs, dann hat man sich in so einem Spinnennetz
von Dingen verheddert,
bevor man auch nur eine Zeile
produktiven Code geschrieben hat und dann ist man mit den Dicts und
den Miscomprehensions so lange fertig.
Und damit hat er nicht so
ganz Unrecht. Also tatsächlich ist es so,
das dickst, wenn man das beherrscht und
so wirklich verstanden hat, wie das funktioniert, mit eben
vielleicht noch Dick-Comprehensions,
vielleicht noch Generator-Expressions würde ich
dazu nehmen und List-Comprehensions.
Damit kann man
einen Großteil von dem, was man so im Alltag an
Programmierproblemen hat, tatsächlich lösen
und es ist
sehr, ja, man kommt da schnell
hin. Sehr convenient und halt
dem Python-Prinzip gar nicht.
Das ist auch
so ein bisschen die Stärke von Python.
Ich muss auch
gelegentlich andere Sprachen machen, jetzt so ein bisschen
TypeScript kommt auf mich zu und
C-Sharp
und da sind solche Mapping-Typen
einfach unhandlich, die sind einfach
schwieriger zu benutzen.
Du musst definieren,
was da für Typen drin sind, nicht in TypeScript.
In TypeScript kannst du einfach,
der Trick an TypeScript, kannst du einfach immer Annie sagen.
Jeder Typ ist Annie
in TypeScript, aber in C-Sharp
kannst du das auch machen, kannst du auch
Annie sagen, aber
wird nicht gerne gesehen.
Mein Lieblingstalent wird Andy übrigens, der sagt, das reicht ihm nicht.
Ja, okay, gut.
Das ist eine Einstellungsache, das kannst du ja abschneiden.
Ja, kann ich.
Das geht trotzdem.
Aber es ist einfach unhandlicher.
Und das ist auch sowas, wenn man sich an diese Art zu denken gewöhnt hat,
dann sieht man auch überall Dictionaries.
Und dann will man sie auch überall verwenden.
Deshalb mir fällt die Schauprogrammierung sehr, sehr schwer,
weil ich mir ganz oft denke, ja, da könnte ich jetzt einen Dictionary verwenden,
aber kann ich an der Stelle nicht.
Ja, muss nicht so viele Spiele programmieren.
und muss aber zwölf Umwege
machen.
Ich sehe aber auch, also
ich sehe auch den Vorteil von diesem Typing an.
Ich bin da ganz klar auf der
Seite der jungen Hüpfer wie dir, Jochen.
Und das ist für mich so ein bisschen
diese, es gibt ja diesen klassischen
Kampf zwischen Explore and Exploit,
wo jeder entscheiden muss, was
er machen muss, um ein Problem
zu lösen. Also Explore ist unbekannte
Dinge angucken und Exploit ist bekannte
Dinge so lange gegenhauen, bis es irgendwie kaputt geht?
Ja, genau. Also Explore heißt
Lösungen ausprobieren, die
dir selber noch nicht bekannt sind.
Also suchen quasi. Und Exploit
heißt Dinge anwenden, die du schon weißt.
Und
Menschen sind da halt sehr unterschiedlich
und das ist tatsächlich wohl so, dass das mit dem Alter
eher zu Exploit geht
als zu Explore, was ja auch okay ist, weil
du viel Explore schon gemacht hast
und dann eben die Dinge
anwendest, die du schon weißt. Wenn du mehr weißt, ist das
natürlich effektiver, als wenn du weniger weißt. Kinder machen
viel, viel mehr Explore. Wusstest du, dass einige
Hacker schon von Anfang an Greise
im Kopf gewesen sind? Ja, das
Man muss sich das auch manchmal wieder zurück
in den Kopf rufen, dass man vielleicht
gelegentlich wieder Explore machen muss. Das ist auch der Grund, warum
ich C-Sharp und TypeScript und so weiter mache, damit
man mal ein bisschen wieder was anderes macht. Ich dachte, C-Sharp
machst du, damit du endlich noch ein Spiel realisieren kannst.
Ja, irgendwie muss man
ja sein Schloss sicher arbeiten.
wie erschlossen arbeiten
das spricht sich doch schon von alleine
ja Erben
ich glaube
oder erobern
Schlösser müssen eigentlich geobert werden
mit Verteidigungsanlagen oder Heirat
ja das ist auch eine Art
der Eroberung
sieht bei mir
jetzt nicht so gut aus
ich bin schon verheiratet
und mit Erben
ich habe meinen Vater gefragt
im Inventar.
Hast halt die hübsche genommen, ist eine schlechte Entscheidung.
Absolut.
Und hübsch und schlau, das sind ja schon zwei Ereigenschaften,
die man sonst nicht im Paket kriegt.
Hat sich mein Vater gefragt,
wann ich als Erbpatter direkt die Schlösser austauschen lasse.
Ja, aber das ist eben,
man muss sich auch immer wieder in den Kopf rufen,
dass man ein bisschen Explore macht und nicht nur Exploit.
Also nicht nur das anwenden, was man kann,
sondern auch mal was ausprobieren, was man noch nicht kann.
Und Dictionaries und Typing gehören halt dazu.
Es gibt so eine witzige Liste von,
wie man Programmiersprachen beschreiben kann.
Und die fangen alle an mit, what if everything was?
Und C zum Beispiel, bei C ist das Mandat,
what if everything was a pointer?
Und in Java ist, what if everything was an object?
Und Python ist halt
what if everything was a dictionary?
Und das ist schon so. Dictionaries sind so ein bisschen
der Kern von Python.
Die sind leicht zu verwenden, die sind sehr mächtig,
man kann so gut wie alles damit machen und
die
formen dann so ein bisschen das Denken.
Jetzt haben wir es ein bisschen verherrlicht, weil wir jetzt noch gar nicht die Nachteile
davon erklärt haben. Warum wollen wir das denn vielleicht
nicht benutzen? Nachteile?
Was könnte es jetzt noch für Nachteile geben?
Es ist O von 1, es kann alles speichern,
das ist großartig. Also vielleicht so wie
Speicherverbrauch. Ja,
Ja gut, das haben wir am Anfang schon gesagt.
Also ein Dictionary verbraucht direkt
ein Viertel Kilobyte.
Das heißt, bei so Embedded Programming oder irgendwelche
IoT-Sachen ist das dann
vielleicht nicht die richtige Wahl.
Es ist auf jeden Fall
relativ wasteful.
Also man hat immer einen großen
Overhead. Immer mindestens
50 Prozent Overhead. Wir laufen alle auf so Kisten, wo wir genug
Speicher haben, da ist das wurscht. Ja, natürlich.
Das ist die Ausrede, die man heutzutage macht. Aber es gibt
natürlich auch Fälle, wo es eben nicht so der Fall ist.
Oder wo man an die Grenzen kommt.
Ja, so eine Waschmaschine hat halt 4 Kilobyte Hauptarbeitsspeicher.
Wenn du 100.000 TPS machen kannst statt 1 Million und du brauchst dann 1 Million, dann wird das halt schon irgendwann relevant.
Ja, Moore's Law wird alles gut machen langfristig.
Auch eine Waschmaschine bekommt dann mehrere Gigabyte Speicher für einzelne Waschbocken.
Ja, Waschmaschinen haben ja heutzutage schon mehr Hauptspeicher.
Irgendwann musst du da einfach mal noch so Grundrohstoffe reinkippen wie, keine Ahnung, weiß jetzt nicht, Sand und Salz oder sowas.
Und da baut es automatisch Waschmittel raus
und das perfekt für die Wäsche
geeignet ist.
Du kannst doch schon so
Waschmaschinen, Waschmittel, Cartridges kaufen
und die werden dann auch so dosiert,
dass es für den Waschmittelhersteller optimal ist.
Okay.
Für den Waschmittelhersteller,
das ist natürlich, ja, egal.
Ja, leider nicht.
Ich hoffe, euch hat eure Folge, unsere Folge zu Dix
heute gefallen. Falls dir noch irgendwas dazu einfällt,
dann...
Ich glaube, Pics und sowas machen wir irgendwann anders.
wir sind auch schon. Ja, ich glaube, wir sind jetzt heute weit
fortgeschritten. Also mein Lieblingsmodul
in Python ist ja
Buildings.dict. Das ist mein Pick der Woche.
Okay.
Ich mache dann einfach von einem Padentic.dict.
Ja, okay, perfekt.
Und Jochen macht Name-Tubel.
Ja, Adress eher.
From Jochen Imports.
Die eigene Implantierung, ja. Aber genau, kann man sich
auf jeden Fall auch mal angucken. Das lohnt sich.
Da haben wir doch Picks gemacht.
Ging schnell.
Ja, dann bleibt uns gewogen,
hört uns immer, wo ihr uns hören wollt und
eine schöne Zeit und bis zum
nächsten Mal. Bis zum nächsten Mal.
Bis zum nächsten Mal. Tschüss.