Transcript: Das Python Importsystem

· Back to episode

Full episode transcript. Timestamps refer to the audio playback.

Ja, hallo liebe Hörerinnen und Hörer, willkommen beim Python-Podcast in der Episode Nummer 33.

Die hatten wir letztes Mal ausgelesen. Deswegen müssen wir die Episode Nummer jetzt ergänzen.

Ja, was machen wir heute? Wir wollen heute über Imports reden. Hi, Jochen.

Ja, li, hallo, willkommen Dominik.

Hi, Johannes.

Ja, hallo, ich bin auch mal wieder da.

Ja, wir kennen uns ja alle schon.

Ja, also über das Python-Importsystem wollen wir heute sprechen.

Vielleicht ein paar kleine News vorweg, wie wir das gerne tun.

Und dann gehen wir so ein bisschen in die Details.

Habt ihr News mitgebracht?

Ja, also die einzigen

News, die ich habe, ist, dass Apple sich gerade den

größten PR-Unfug aller

Zeiten einholt. Aber

da ich kein Apple-Gerät habe, geht es

ein kleines bisschen mehr. Das Problem habe ich auch nicht.

Jochen, erzähl du doch mal.

Ja, nee,

tatsächlich ist es PR-technisch, würde ich

sagen, auch aus meiner Perspektive ein großer Unfall.

Wenn man sich jetzt anguckt, was sie

technisch tun, ist es nicht so furchtbar schlimm.

Was ist denn überhaupt passiert? Vielleicht jetzt mal so die Story.

Sie haben irgendwie

War das eine Pressemeldung?

Es war eine Pressemeldung und es war eine technische Meldung, glaube ich,

dass sie jetzt CSAM

angemacht haben, Contact Content Scanning

and

keine Ahnung, was es bedeutet.

Ja, jedenfalls

wollen sie, jedenfalls will

Apple jetzt in die Fotos reingucken und

verbotene Inhalte finden.

Ja, das ist natürlich

so ein bisschen, das, ja.

Mit modernster Technologie.

Ja, zum Glück

ist es nicht das Schlimme.

und Technologie, was man halt auch nehmen könnte,

sondern es ist halt irgendwas total Billiges,

einfach nur Hashes in Bildern angucken.

Also im Grunde nur gucken, ist das ein

Bild, das auf irgendeiner Liste draufsteht

von verbotenen Bildern.

Ja, aber haben die nicht auch gesagt, dass sie so

neuronale Netze drüberlaufen lassen

und dann Sachen erkennen wollen?

Oder ist das erst der nächste Schritt?

Ja, genau, das ist halt der

Agau-Teil. Ja, genau, und das ist auch so ein bisschen

der Präzedenzfall.

Früher war Apple ja immer so, ja,

es ist auf deinem Gerät und es ist alles sicher und wir können

da gar nicht. Und jetzt ist es so, ja, wir gucken doch mal rein.

Ja, also

entweder war es ein Unfall,

sozusagen, dass jemand nicht drüber nachgedacht hat,

dass, wenn man das so sagt, dass das dann genau

das auslöst bei den Leuten.

Oder es ist halt irgendwie, aber das kann ich

mir auch nicht vorstellen, weil das wäre ja so

ein abrupter Strategiewechsel. Das wäre auch schon

irgendwie komisch. Also insofern nehme ich mal an,

dass es eher ein PR-Unfall ist.

Man weiß es nicht. Aber es ist ein

Präzedenzfall. Apple scannt jetzt Inhalte

auf euren Geräten.

Das machen sie

Das machen sie ja auch sowieso schon immer.

Also man kann ja auch in der Fotos-App

irgendwie nach Hund gucken

oder nach Personen oder sonst irgendwas.

Und da ist tatsächlich, das ist halt die gute Technik

sozusagen, die da verwendet wird.

Und ja, man kann sogar...

Aber auch da sind viele Sachen falsch einsortiert.

Ja, aber sie sind da auch

halbwegs schnell und so. Man kann auch nach

Vaccination oder so suchen und dann findet es den Impfpass,

wenn man den fotografiert hat und so.

Also da machen sie auch wirklich das gute

Zeug.

Und machen das halt

auf dem Gerät selber.

Aber genau, nur halt, wenn man selber sagt, man hätte das gern und ja, und halt, es wird auch nicht an irgendwen geschickt. Und jetzt ist das natürlich eine andere Sache, wenn sie jetzt irgendwas eines von den verbotenen Bildern findet, dann sagt es irgendwie dann Petzl.

Vielleicht verbotene Bilder?

Ja, wer weiß.

Genau, und wir wissen auch, dass es da welche gibt, ja. Also das ist natürlich alles sehr unangenehm und das wäre dann schon ein Präsenzfall, weil das haben sie bisher nicht gemacht.

Na gut, mal sehen, wie sich das entwickelt. PR-mäßig ist es auf jeden Fall ein mittleres Resultat.

und das ist von einem Impfpass gesagt, das heißt, du bist auch jetzt durch.

Ich bin schon lange durch.

Ich auch jetzt seit einer Woche.

Also hier auch nochmal der Aufruf von allen Zuhörern, lasst euch bitte impfen.

Ja, das ist eine gute Idee.

Wie viele haben wir jetzt verloren?

Die Zuhörer.

Es gab so einen tollen Rant-Post von Linus Torwalser.

Ja, der sagt auch, lasst euch impfen, ihr Trottel.

Ja, genau.

auf der Tour.

Ja, Linus Torwalds

benutzt noch mehr ausgewählte Wörter,

um das zu beschreiben, sagen wir es mal so.

Ja, aber inhaltlich

doch. Inhaltlich war es die Zusammenfassung, ja.

Ja, haben wir noch Python-News?

Ja, also eine

News, die so ein bisschen anschließt an

unsere letzte Episode zu Packaging,

ist, dass tatsächlich,

das war vielleicht schon länger klar,

aber mir war es halt noch nicht klar, ab

Python 3.11

wird Distutils

halt deprecated.

Und das heißt,

man muss sich da an der Stelle dann halt mal was überlegen,

was man dann so tut.

Aber es gibt doch so viele Alternativen.

Ja. Diverse Alternativen.

Also die

Pakete, die jetzt halt so

ein richtiges Problemchen bekommen,

sind halt sowas wie

NumPy und SciPy und so, weil

die haben nämlich, die erben nämlich von

Distutils und haben da Extensions für gebaut

und damit bauen sie halt alles.

Ja, okay.

und ja,

also die gucken sich gerade andere Sachen an

und

tatsächlich gibt es da, also sie haben sich zum Beispiel

CMake angeguckt oder halt auch

Mason heißt das irgendwie

und tatsächlich

also ich manchmal, also sogar relativ

häufig, ich habe ja hier so ein M1

Mac auch und da passiert

es durchaus, also wenn die Python-Version hochgeht oder so,

ist es eigentlich immer so, dass wenn ich dann

Projekte habe, die

abhängig haben zu NumPy,

Pandas oder so, dass das Ganze zwar kopiert werden muss,

weil meistens ist das Update von Python halt schneller bei mir, als die Wheels draußen sind.

Und dann muss ich das halt kompilieren und dann denke ich mir so, oh nein, jetzt dauert das wieder ein paar Minuten.

Und tatsächlich dauert das bei NumPy, glaube ich, sieben Minuten irgendwie mit dem klassischen jetzt des Tutels.

Und tatsächlich aber auf Mason basierten, hat hier jemand schon den Namen vergessen, angefangen damit rumzuexperimentieren, dauert es halt irgendwie noch vier Sekunden oder so.

Also es ist hauptsächlich irgendwie

Bauzeit,

die da

benötigt wird.

Also insofern, mal gucken.

Könnte sein, dass es alles schneller wird demnächst.

Das wäre auch ein sehr positiver

Effekt von dieser Deprecation.

Genau. Und ansonsten,

ja, ich glaube 3.11

ist in der Beta.

3.10 ist in der Beta.

Ich glaube, jetzt um den Dreh

ein Rieskandidat.

Genau.

Die Zahlen gehen so schnell hoch.

Ja, ja, ja. Freuen wir uns schon.

Also ich habe mal den GitHub Copilot,

den wir auch schon mal kurz erwähnt hatten, ausprobiert.

Da habe ich jetzt auch eine Beta-Einladung bekommen.

Muss sagen, das ist echt toll.

Also ich habe noch nie so einen

super Effekt von einer KI erlebt.

Ich finde es echt nice. Ich gebe ein, also ich habe

jetzt die VS Code Extension dafür benutzt.

Sowas wie Define and Fibonacci oder sowas.

Und dann warte ich

auf das Autocompletion und dann schreibt er mir die komplette

Funktion inklusive Docstrings und Type Annotations

als Type-Int und ich drücke einmal

Tabulator und es ist fertig. Und das geht

halt auch für Sachen, die ich selber schreibe. Wenn ich jetzt

eine Klasse schreibe, verschiedene Methoden nehme, beispielsweise

irgendwie HTTP-Methode.

Ich habe jetzt irgendwie ein Get geschrieben, ne, in einer Klasse.

Define, Get, bla bla bla. Und danach

fange ich an mit Define und dann steckt er mir

als nächstes vor, Post zu definieren.

Und zwar auch mit genau den richtigen Parametern und so.

Das sind solche Sachen, das ist halt einfach,

der lernt halt aus seinem eigenen Code raus und das ist

wow. Also ich bin wirklich beeindruckt davon,

was das so macht. Also das ist so ein bisschen,

man braucht keine Snippets mehr, ja, wenn man irgendwie

Snippets-Sammlung hat, sondern man nimmt halt einfach dann

das individualisierte Snippet und das ist

und Jochen unterhalten sich über die Programmiersprache Python

Modelle trainiert werden?

Nein.

Das ist halt etwas, was sich allmählich einbürgert.

Der Begriff dafür nennt sich

Self-Supervised Learning.

Und zwar deswegen, weil man halt

zum Beispiel auf Text

relativ gut Modelle trainieren kann,

ohne irgendwelche gelabelten Daten

haben zu müssen. Was man ja normalerweise ist, ist immer das Problem

bei

irgendwie, wenn man so überwachte

Modelle, also

anführungsweise normale Machine Learning Modelle

trainiert, dann braucht man halt Trainingsdaten

und damit meint man üblicherweise halt

Daten, wo man

Labels dran geschrieben hat, wie zum Beispiel

jetzt, wenn man jetzt Bilder hat, so was ist ein Hund, das ist eine Katze

und das ist, weiß ich nicht, irgendwas

dazwischen oder so

und

bei Texten hat man das ja auch,

da gibt es dann ein klassisches Problem wie Textkategorisierung,

da hast du halt einen Text und dann steht halt zum Beispiel so

diese Newsreuters-Artikel, da steht dran,

das ist jetzt Sport oder das ist Politik oder das ist halt irgendwas anderes

und

und... Cool wäre ja so das Label wie, will ich lesen, will ich nicht lesen?

Kann man auch alles machen.

Wenn du da Trainingsdaten hast, dann kannst du Modelle drauf trainieren, die dann auch wahrscheinlich

halbwegs gut funktionieren sollten, also das geht alles. Aber das Problem ist

natürlich, dass für die meisten Probleme, die man so hat, hat man halt eben keine Trainingsdaten und das

Erstellen von Trainingsdaten ist halt so aufwendig, dass sich das dann meistens nicht lohnt, das zu machen.

Wie viel braucht man denn da, ungefähr 100.000? Also kommt drauf an, wie gut es sein soll.

und dann entsprechend

unter Umständen schon Millionen von Beispielen oder so

und das ist dann halt doof, weil das ist einfach zu viel.

Die meisten Leute haben so viele Beispiele gar nicht.

Nee, genau. Also einmal, du hast

gar nicht genug Beispiele, um sie labeln zu können,

dann musst du die erstmal besorgen, dann musst du es auch noch irgendwie labeln

und dann hast du Fehler in den Labels, weil

halt die Leute das nicht perfekt gemacht haben und dann

musst du das irgendwie kontrollieren und

dann schwuppdiwupp hast du irgendwie so ein Redaktionssystem

und eine Redaktion, eine technische Redaktion

und dann Prozesse und

keine Ahnung und Abstimmungen und das kostet

Schweinegeld und das macht dann halt keiner so einfach so.

Sondern nur, wenn man es halt wirklich, wirklich braucht.

Und

ja, aber

man kann halt aus Text auch

lernen, ohne diese ganzen Geschichten

haben zu müssen. Also

es gab ein Paper 2017,

ist das glaube ich irgendwie, Attention is all you need.

Da wurde halt diese Transformer-Architektur

eingeführt und

diese

Dinge funktionieren auf Sprache halt total super.

die funktionieren so,

und Jochen unterhalten sich über die Programmiersprache Python

in die Richtung, dass es das halt beim nächsten Mal besser macht.

Und das machen wir dann ganz oft

und dann kann es halt

aus einem Text, ohne dass man da irgendwelche Labels

explizit für bräuchte oder so,

Dinge lernen, und zwar fast alles.

Und das ist halt das Interessante.

Man kann das gesamte Internet nehmen

und dann lernt es halt

lustigerweise eben nicht nur

irgendwie so stumpf, welches Wort

die höchste Wahrscheinlichkeit hat,

dazustehen, sondern um das gut machen

zu können, lernt es halt auch eine ganze Menge

Konzepte und wie Dinge in Verhältnissen

stehen und solche Sachen. Auch Kontext tatsächlich,

das ist halt spannend. Also zum Beispiel

das Plugin schafft das halt auch,

Kommentare richtig zu schreiben. Das heißt, ich fange

mit einem Kommentar an, zwei Worte, und das macht

einen relativ guten Vorschlag für, was da stehen sollte.

Ja, ja, ja, genau.

Das ist eine

Geschichte, die man halt auch machen kann, dass man sagt,

okay, das ist ein Text, der Rest ist halt Lücke,

dann füll mal. Und dann kommen da auch

schon ganz interessante Geschichten bei raus.

Also wenn man sich diese generierten Texte

anguckt, dann ist halt schon immer so, dass man

irgendwann wird so leicht absurd oder

sehr verdreht irgendwie und

merkt so, okay, so ganz, schon so ein bisschen

neben der Spur. Ja, man kann es halt schnell kaputt machen.

Ja, die nähern dann auch so ein bisschen.

Wenn man halt so ein bisschen nicht falsch ist.

Kann man es schnell kaputt machen,

dann kann es immer so. Ja, ich habe noch

was dazu gelesen,

was in eine andere Richtung geht, dass es jetzt

wohl eine große Anzahl inzwischen von

wissenschaftlichen Veröffentlichungen gibt,

denen man durch Analyse

ansehen kann, dass eben nicht von

im Menschen geschrieben würden, sondern von einem neuronalen Netzwerk.

Und die Technik,

die die da verwendet haben, die ist total witzig,

weil diese Netzwerke für

so Paper-Generierung

und für Text-Generierung generell,

die werden wohl bestraft, wenn sie Plagiate

erzeugen. Weil das willst du natürlich nicht.

Du willst natürlich nicht ein Paper einreichen, das dann als Plagiate

abgerichtet wird. Und deshalb

wählen die sehr viele Synonyme.

Die sprechen sehr viel in Synonymen.

Und auch eben so Fachbegriffe

werden dann oft in Synonymen

genommen. Das nette Beispiel,

was ich erkenne, war eben, dass da die Paper

über Big Data, die haben die ganze Zeit über

Colossal Information gesprochen.

Was eben kein normaler Mensch

schreiben würde. Und dann haben sie eben gesucht, wie oft

dieser Begriff

Colossal Information in den Papern

vorkommt und die dann eben genauer

angesehen und die hatten eben

alle diese Anzeichen von erzeugten Papern.

Und das ist so ein bisschen jetzt quasi

die Kehrseite von Copilot, dass die eben nicht

nur, man muss es dann trotzdem noch für was

Gutes einsetzen und nicht für

Ja, du bist ja schon

da, du brauchst Pages beizutreiben.

Ja, aber

genau, was ich

noch erwähnen wollte, war,

genau, man kann jetzt halt sozusagen Modelle trainieren

auf allen Texten, die es im Internet gibt

und die lernen halt tatsächlich da auch

Dinge dann raus und das ist natürlich total super und das geht

bei Sprache vor allen Dingen deswegen, weil

man halt eine endliche

Anzahl von möglichen

Füllern

sozusagen für die Lücken. Was? Noam Chomsky

würde dir widersprechen, Jochen?

Ja, ja gut. Aber man kann sich da ja beschränken.

Man kann ja sagen, okay, meine Sprache hat nur

20.000, 30.000

Vokabeln

und das war's. So größer ist mein Vocabulary

einfach nicht. Ja, okay. Und wenn du immer nur ein Wort

rausnimmst, ist natürlich klar. Und unter denen

wird auch eins sein, das hinreichend nah dran ist.

Und dann kannst du eben allen Worten

eine Wahrscheinlichkeit zuweisen. Du kannst halt sagen,

okay, das ist jetzt sehr, sehr unwahrscheinlich

und das ist jetzt irgendwie, dass das geht.

Das sind alle sehr unwahrscheinlich.

Es gibt dann bestimmt das Wort wie F, das was überall hinpasst.

Ja klar.

Aber das Modell,

das dann halt auch, das Modell, das

damit trainiert wird, passt dann aber nicht mehr überall hin, wenn du das

als akzeptiert hast.

Kennen wir leider.

Jedenfalls, genau.

Also mit Sprache geht das

total super und eben

Copilot ist halt dann

quasi auch eine Folge. Das Tolle ist, dass man

jetzt. Modelle, die da drauf trainiert sind,

kann man jetzt mit ganz wenig Trainingsbeispielen

auf das

Problem, das man wirklich hat,

adaptieren. Also da braucht man dann nur noch

ein paar Trainingsbeispiele, also

nicht mehr viele. Ja, ich glaube auch,

er macht das tatsächlich anhand des Repos,

was du gerade auffasst. Kann er schon gucken

und kann da schon dann die Completion zum Beispiel oder die

Vorschläge anpassen auf das, was du da gerade machen

willst. Und das ist schon echt wow.

Ja, und das ist halt natürlich total toll, weil

das dann halt läuft,

dass du im Grunde dieses Trainingsproblem

Trainingsdatenproblem loswirst.

Und ja,

eine ganze Menge Anwendungsfälle

plötzlich von, ist zu aufwendig,

unlösbar, lohnt sich nicht, in Richtung

kann man schon mal probieren,

wandern und dann ist es natürlich toll.

Und ja, also da wird es

eine Menge interessante Anwendungen geben.

Also gerade für die ganzen V-Programmierer unter uns, also das ganze

Zeug drumherum, das geht halt einfach jetzt viel

automatisierter.

Ja, Kinderregegen, das ist schlecht für die

Auftragsprogrammierer.

Das finde ich nicht gut.

Das kann schon sein.

Ja.

Aber genau, das Problem

ist aber jetzt, dass man das nicht

machen kann für, also was halt, also

man würde, wäre sehr viel weiter,

wenn man das jetzt auch für zum Beispiel

Bilddaten machen könnte. Also und

tatsächlich ist es wohl so, dass es da

gibt es auch inzwischen Forschung zu,

das ist halt tatsächlich der Weg, also man hat sich ja das

oft lange, oder ich erinnere mich noch dran,

dass es mal völlig unklar war, wie das

eigentlich funktioniert, wie lernen Kinder eigentlich

sozusagen so schnell Dinge, man versteht es nicht, sie sehen eigentlich zu wenig Trainingsbeispiele

für das, was sie da lernen und tatsächlich lernen sie ja auch so etwas, was einem die

Forschung sagt, manchmal Schwierigkeiten hat, das einfach so zu akzeptieren, aber die sagt

halt, das meiste, was Menschen so lernen, lernen sie halt so in den ersten neun Monaten

und alles, was danach kommt, ist halt so, naja Gott, also ich meine so Details, also

Die wesentlichen Dinge sind bis dahin gelernt.

Wie machen die das denn?

Kinder in dem Alter verstehen einfach gar nichts.

Die kennen auch keine Worte für nichts.

Wieso können die denn so viel lernen?

Wie soll das gehen? Das ist irgendwie alles seltsam.

Und tatsächlich ist es wohl so,

dass die halt auch schon eine Art

Self-Supervised Learning machen

und quasi genau das gleiche Prinzip irgendwie

sehen halt was

und Dinge passieren

und dann betrachten sie das

sozusagen als eine Art Lückentext und füllen das dann halt

und das funktioniert.

Genau, das ist das Ego, was das dann macht

Na, keine Ahnung

Ja, aber das zieht das dann irgendwo aus dem Äther, irgendwelche

Formationen schafft das dann natürlich und deswegen hast du ja auch

so, weiß nicht, ob ihr das kennt, wenn ihr irgendwo

müde seid oder sowas, dann werden bestimmte Sachen

ja auch einfach ersetzt, der Kopf macht das ja sehr gerne

dass er bestimmte Flecken, die

nicht so ganz klar sind, dann mit Sachen überschreift

also einige Leute, die haben dann auch

innere Stimme, die dann auf einmal das erste Mal vollständig

die nur so halb gehört haben oder

das kannst du auch mit optischen Informationen machen oder mit

anderen optischen Signalen

und das ist halt super spannend tatsächlich

und wenn das halt self-supervised learning ist,

dann ist ja auch klar, dann hast du so ein Lückenbild.

Das ist so ein bisschen so, du hast ein Foto,

da fehlt ein Teil und dann wird das automatisch ersetzt.

Das ist spannend, wenn die KI das kann, dann kann man

quasi, machst du ein Hochzeitsbild von dir, dann kannst du irgendwie

deinen Partner rausschneiden, dann kannst du den idealen Partner auf einmal sehen.

Ah ja, und

so ist also dieses Python

Import-System entstanden.

Das ist ja spannend.

Wie, willst du jetzt zum Topic zurück?

Nein, nein. Nur ganz kurz, also

das, was halt momentan nicht geht, was man nicht

hinkriegt und was halt total toll wäre, wenn man es irgendwie hinkriegen würde,

also vielleicht hat ja irgendjemand eine Idee

das große ungelöste Problem an der Stelle ist halt

wenn du jetzt ein Bild aus einem

Teil aus einem Bild rausnimmst und sagst so

das ist jetzt leer, also einmal

man kann halt irgendwie die

Menge an Bildern, die halt an der Stelle möglich wären

nicht aufzählen, nicht so richtig

und dann ist es so

selbst wenn man sich irgendwie beschränkt

weiß man nicht, so jetzt hat man

zwei Sachen, die eigentlich offensichtlich nichts damit zu tun haben

mit dem Bild, das man eigentlich an der

Stelle gerne hätte, welche Wahrscheinlichkeit weiß man

hinzu und wie ist der Gradient in welche Richtung.

Aber vielleicht braucht man da den Kontext für, weil wenn du einen Kontext

hast, in dem das drumherum gestellt werden soll,

der halt selber ein Objekt ist,

das viele verschiedene Informationen beinhaltet, dann ist es

besser, diese Menge an

abzählbaren Elementen zu bilden und das entsprechend

herauszusuchen mit der höchsten Wahrscheinlichkeit.

Das heißt also, ohne Kontext ist das wahrscheinlich nicht so

einfach möglich, dass du einfach so ein Bild machst, das dann gut trifft.

Aber wenn du Informationen über den Kontext hast,

in dem du dieses Bild ersetzen möchtest...

Also der Punkt ist eher, das ist ja möglich.

Also du kannst ja durchaus ein Modell trainieren,

was dann irgendwas vorhersagt an der Stelle.

Die Frage ist nur, welchen Wert hat das, was es jetzt vorhergesagt hat?

Hat das jetzt die Wahrscheinlichkeit 0,376 oder 0,652?

Und das macht ja einen Unterschied fürs Training, aber es ist halt völlig unklar, wie man da die Wahrscheinlichkeit ausrechnen soll.

Ja, vielleicht braucht man dafür echt einen Kontext, in der es eingesetzt werden soll.

Das ist, glaube ich, gar nicht so.

Ja, also das ist auf jeden Fall, wenn da jemand eine Idee hat, voll gut.

Aber das war jetzt auch gerade wieder so ein Ding, was halt passiert, wenn man halt den Kontext nicht hat.

dann passiert sowas wie ein Relative Import

Beyond Top Level Package oder so.

Oh, das ist ein Syntaxfehler quasi.

Ich sehe schon, es gibt eine gewisse

Abschüssigkeit in eine

bestimmte Richtung. Ja, Importsystem ist auch

voll interessant. Na gut.

Ja, natürlich, das war gerade ein

Versuch, da so ein bisschen hinzukommen, weil wir wollten ja über das

Importsystem tatsächlich reden und

wie man das in Python macht.

Und ich glaube, als Basis irgendwie das so ein bisschen zu verstehen,

es gibt einen super tollen Blog, den ich auch erst letztens

entdeckt habe, der 10.000 Meters heißt,

der irgendwie auf Hacker News nochmal gefeatured worden ist und da hat ein

Mensch namens Viktor Skvorstov, wenn ich ihn richtig ausspreche,

einen Artikel geschrieben, wie das Python-Import-System funktioniert.

Und das hat er so ein bisschen erklärt, das ist sehr spannend zu lesen.

Fangen wir auf jeden Fall in die Shownotes. Und ja, wie funktioniert denn das eigentlich?

Was ist denn das Python Ja ich habe diesen Artikel auf Hacker News gesehen und auch die Diskussion dann so ein bisschen angeguckt und da ist mir aufgefallen dass das doch tats erstaunlich

viel komplizierter ist, als

man das so denkt oder als man das im Kopf hat.

Was mir gar nicht so aufgefallen

war, weil ich offenbar

nicht alle Features benutze, die es da so gibt.

Vielleicht ganz kurz, bevor wir darauf einsteigen,

was ist denn überhaupt das Problem damit?

Wir haben so eine Story gehört, dass das mal lange

macht, was macht denn das?

Worum geht es denn da überhaupt?

Und warum braucht Python ein Import-System überhaupt?

Das ist ja auch eine spannende Sache, weil in anderen Sprachen ist das ja anders

gelöst und zum Teil besser und zum Teil

schlechter.

Wer will

anfangen?

Ich würde sagen, vielleicht kann man genauso anfangen wie der Artikel.

Was passiert denn, wenn man sagt Import M?

Warum sagt man das denn überhaupt,

Jochen?

Es gibt

natürlich Build-Ins, aber nicht alles sind

Build-ins und manchmal möchte man halt

irgendwo Funktionen oder Klassen oder sonst

irgendwas verwenden.

Oder man möchte einfach seinen Code trennen

und nicht alles in eine einzige Pfeile.

Man möchte halt irgendwas verwenden, was nicht in der aktuellen Datei definiert ist.

Genau.

Und jetzt könnte ich verschiedene Dinge,

ich könnte mir die Datei nehmen und sie

e-ballen, könnte ich machen.

Ja.

Wäre

auch möglich, oder?

Wäre auch möglich.

Hat auch einen ähnlichen Effekt irgendwie.

tatsächlich. Aber das

überschreibt dann natürlich manchmal Sachen, wenn ich jetzt irgendwie

zum Beispiel da drin halt,

wenn ich jetzt im aktuellen... Ja, vor allem, wenn man das rekursiv

macht, weil das müsste dann auch immer weiter funktionieren.

Ja. Und dann

wenn man so Counter-Variablen hat oder so,

die sind dann wahrscheinlich hinterher anders.

Vielleicht, ja. Vielleicht. Ja, oder auch

Namen, die einfach gängig sind,

werden vielleicht eventuell überschrieben.

Ja, aber das ist ja, bei Python macht der auch

irgendwie sowas, ne? Das macht ja so ein

Namespace wieder. Ja, genau. Aber das müsstest du dir

dann, also wenn du einfach die Datei lädst

und ausführst, also

e-Val drauf machst, dann

ja, kriegst du halt erstmal alles in die Hand.

Und da wäre dann, hätte man

dann auch wieder das Problem mit dieser Dekursion, die müssen wir auch irgendwie

lösen, weil du musst ja dann eventuell noch mehr Sachen

derweil

importieren und e-Valen und

vielleicht hast du ja sogar das Problem, dass

du es zyklisch machst.

Aber das Problem haben wir in Python auch.

Das Problem haben wir in Python auch, ja, aber

müssen wir mal überlegen, wie das das macht.

Aber in anderen

Sprachen, um da noch kurz drauf anzugehen,

braucht man es ja, macht man es ja

nicht. In Java oder in C++

macht man es ja nicht, dass man einfach

andere Dateien da reinkopiert,

weil da ja

die Organisation anders ist. Da braucht man ja quasi

keine Objekte in der Hand, sondern nur

einen Verweis auf die entsprechenden Stellen

im Code. Das heißt, bei denen

funktioniert das Import-System halt,

weil das während des Kompilierens passiert,

deutlich anders

als in Python.

Ja, ich überlege gerade, wo da die Unterschiede sind.

Also wenn ich in C sage include,

das wäre das eine Datei.

Genau, aber wenn du zum Beispiel in C

includeierst, die sind ja normalerweise nur .h-Dateien.

Und da sind ja keine Definitionen drin,

da sind ja nur Deklarationen drin.

Da steht nur drin, es gibt etwas, was heißt so und so.

Und das ist das Einzige, was du an der Stelle da reinkriegst.

Das Zusammenführen, was dann tatsächlich der Code ist

oder was diese Werte sind. Das passiert erst später

im Link-Vorgang, wenn

du schon alles kompiliert hast. Und diese

Phasen gibt es bei Python ja einfach überhaupt

nicht. Bei Python gibt es ja nur die Phase

Ausführen. Und zu dem Zeitpunkt

brauchst du es dann jetzt. Und

was viele Leute vergessen,

wenn du define schreibst, wenn du eine Funktion definierst,

wenn du eine

Funktion erstellst, dann ist

das Code, der ausgeführt wird, das ist ein Befehl

an Python und der heißt,

merkt ihr mal unter dem Namen, keine Ahnung,

fun, ein Code,

Objekt, was folgende Eigenschaften hat.

Es ist callable und dieser callable hat

folgende Parameter und dann steht da

Code drin und so weiter und so fort. Und auch

bei Class, wenn du Class

als Schlüsselwort, wird ja erstmal

alles ausgeführt, was da drin ist. Das heißt, du kannst da

prinzipiell Code drin haben, der

Sachen tut, was ja auch an vielen Stellen

sehr wichtig ist, was du aber in anderen

Systemen nicht hast.

In der Java und in der C++

hast du das nicht, das wird nicht ausgeführt.

Es wird zum Teil ausgeführt

bei C, weil du da diesen komischen Preprocessor

hast und weil der auch so

constant optimizations

versucht schon mal zu machen,

aber generell wird

C-Code erst ausgeführt, wenn du das Programm startest.

Das ist bei Python,

ja, also diesen Schritt des Kompilierens gibt es ja bei Python

nicht, der ist ja da so ein bisschen innen drin.

Das heißt, du kannst auch mit Import

kannst du auch Sachen ausführen.

Was

manchmal komisch ist und manchmal gewünscht

und manchmal überraschend.

Ja, also das ist manchmal,

also tatsächlich, wenn Sachen importiert

und das dann halt alles in dem Modul ausgeführt wird,

was auf dem Top-Level ist, das ist halt schon

manchmal eher überraschend.

Warum passiert das denn auch?

Warum wird das dann ausgeführt? Also wenn man jetzt

einen Import hat, Import M

von irgendwo, was dann...

Einfach nur Import M, also wirklich nur

diese Zeile Import M. Was passiert dann?

Ja, das ist eine gute Frage.

Und auf den ersten Blick ist es

finde ich so ein bisschen offensichtlich, was da passiert

und auf den zweiten Blick ist es dann tatsächlich doch nicht so offensichtlich,

wie eben dieser Artikel,

glaube ich, uns allen demonstriert hat.

Also für mich bedeutet Import M

suche eine Datei,

die M.py heißt

und gib mir den Inhalt

davon als Modul. Oh, das wäre aber ein Skript.

Und wir könnten auch ein Modul laden.

Wenn ein Modul heißt, das M heißt,

das ist ein Verzeichnis oder sowas.

Aber ein Verzeichnis ist ja

auch nur so eine Art Datei.

Ein Verzeichnis ist ja auch nur ein

Verweis auf die Init.py.

Es gibt Module und Packages

und was ist denn überhaupt der Unterschied?

was ein Skript, was ein Modul, was ein Package.

Ja, das ist schwer zu sagen.

Ich finde es schwer zu sagen, weil

für mich dieser Unterschied wirklich minimal

ist. Das eine ist halt

eine Datei und das andere ist ein Verzeichnis, aber das Verzeichnis

selber hat ja keinen Inhalt

und deshalb tut man so, als ob die InitPy,

die da drin ist, dass der Inhalt dieses

Verzeichnisses ist.

Genau, in der InitPy kann man auch

sowas wie all dann definieren, das heißt, wenn man zum Beispiel sowas wie

import as quick, dann kannst du auch eine einzelne

Datei machen. Kannst du überall definieren.

Ja, okay.

Kannst du auch Slots definieren, das ist auch, kannst du auch überall machen.

Ein Slot? Ja, das sind solche Sachen, die beim Import mitgebracht werden sollen.

Genauso wie All, wenn du All definierst und dann machst du From M Import Stern, dann kriegst du alles das, was in All drin steht.

Also Unterstrich, Unterstrich, All, Unterstrich, Unterstrich, um es jetzt mal hier korrekt zu sagen.

Dann, dann, All, dann, dann.

Das ist ein sehr guter Mechanismus, den sieht man sehr selten, weil Importsternen ja so verpönt ist, so gerne gesehen wird. Das hatten wir schon in der ersten Vorlesung quasi in Informatik 1, hat uns unser Professor schon gesagt, ja man kann using namespace standard nehmen und dann kann man mal gucken, wie viele Symbole da importiert werden und es waren irgendwie 13.000 oder sowas.

und das kannst du in Python natürlich auch machen,

kannst auch from Stern import Stern

probieren,

kriegst halt auch 100.000 Sachen rein.

Deshalb ist

import Stern,

nee, nee, from Stern import Stern geht nicht,

aber so quasi, wenn du es dir

vorstellst. Import Stern heißt halt,

hol alles aus diesem Modul oder aus dem Package

und gib es mir

und meistens weiß man ja gar nicht

ganz genau, was da drin ist. Meistens weiß man auch nicht,

wie viel da drin ist.

Und ganz oft sind da ja dann

auch lokale Sachen drin, die man eigentlich gar nicht haben

möchte. Oder Imports, die

dieses Modul macht,

die hast du dann auf einmal auch selber

importiert. Subdependencies quasi.

Genau, also wenn du in

der m.py, so wie wir es jetzt eben

drin hatten,

wenn du da import, keine Ahnung, import

x machst, und dann machst du from m

import Stern, hast du auch x importiert.

Weil das halt in dem

Modul m dann schon drin ist. Und das ist genau

der Grund, warum man dieses Stern nicht machen soll, weil man nämlich

nicht weiß, was da drin ist und man halt dann alle...

schon gab, bei einem Lokal irgendwo

überschreiben würde. Und wenn mehrere

Module oder Pakete

dasselbe Namen definieren

für irgendwas, was ja durchaus mal vorkommen kann,

dann weiß man nicht mehr genau, was unter dem Namen jeweils

Identität ist. Aber jetzt müssen wir ja erstmal klären,

was Import überhaupt macht. Wir sprechen

jetzt schon die ganze Zeit so, aber wir wissen es immer noch nicht.

Wir wissen aber immer noch nicht genau, was ein Modul, ein Paket ist.

Ja, also ich glaube,

das eine ist eine Datei und das andere ist

ein Verzeichnis.

Es gibt eine Datei.

Ich glaube, es ist auch irgendwie...

der Datei.

Ich glaube, der entscheidende Unterschied ist, dass

ein Paket Submodule haben kann

und ein Modul nicht.

Also genau, ich habe

eine Definition gefunden,

der irgendwo sagt hat, if a module name

has no dots, it's not considered to be part

of a package.

Aha.

Ja, okay.

Also ein Paket ist

quasi eine Sammlung von Modulen oder sowas?

Ja, okay, gut.

Ja.

Da gab es auch eine tolle Antwort drin, Relative Imports for the Billions Times oder sowas.

Ja, relative Imports, darüber muss man auch noch sprechen. Ich bin ein großer Fan davon, aber offensichtlich nicht so. Gut, da kommen wir vielleicht nach.

Ja, ja, ja, okay.

Also was macht denn Import jetzt überhaupt? Import macht, soll ich mal versuchen, soll ich mal mein Verständnis erklären und er korrigiert mich dann.

Von wo importiert ihr denn überhaupt?

Genau, also Import. Erstmal sucht Import ein, also wenn ich sage Import M, dann sucht das Import-System von Python nach etwas, das M heißt. Und zwar auf dem Python Path.

Auf dem Python Path. Ah.

eine Variable, die heißt

sys.pythonpath

sys.path heißt die, oder?

Ich weiß, ich vergesse es jetzt mal wieder.

Jedenfalls ist da eine Menge

von Verzeichnissen drin und

in der Reihenfolge, wie sie in diesem

Path stehen, wird nach

dem Namen

M gesucht. Also 0 ist glaube ich der aktuelle

irgendwie, dass das

entweder vorne oder hinten, das ist immer

Ich glaube 0, der erste ist immer der, wo du gerade bist.

Punkt. Genau.

also die Datei, wo du gerade aufgeführt bist

oder sowas und dann ist halt quasi, der sucht halt dann

im ersten in 1, wo und ab da

und der erste Hit wird dann genommen

Genau, der erste Hit wird dann genommen und in diesem Path

können ganz viele verschiedene Sachen

drin sein, also die Installation

des Installationsverzeichnisses des Interpreters

und wenn man irgendwelche

Environments aktiviert hat, dann sind die da alle drin

man kann da auch selber Sachen reintun

braucht man manchmal, ist manchmal ganz nützlich

Also wenn man verschiedene Pakete

haben will, die auch importiert werden können

dann muss man einfach da gucken, dass

in this.path quasi in der Umgebungsvariante

Das ist im Wesentlichen das, was

VirtualEnv macht. Er macht ein Verzeichnis, wo

du deine Pakete reinlegen kannst und tut den

in den Python-Path für dich. Genau, das heißt, wichtig,

dass euer Path vernünftig konfiguriert ist, wenn ihr Python nutzt,

weil wenn die falsche Reihenfolge drin ist, dann kann

das sein, dass er im Path von Python

2 sucht oder so, also wie es

früher offenbar war. Und dann habt ihr ein Problem.

Genau.

Also, und er sucht diese ganzen Verzeichnisse durch

und wenn da irgendwas drin ist, was diesem Namen m entspricht,

also eine m.py oder ein Verzeichnis, was m

heißt, was eine InitPy hat, oder

in Python 3 ein Verzeichnis, was

das M heißt und Python-Dateien

enthält, was keine InitPy hat,

dann wird

das als Modul importiert

und in den aktuellen Namespace

als Modul M übergeben.

Wir haben gerade wirklich das schon in Python 2 und 3 diskriminiert,

das ist ja interessant. Ja, da gibt es Unterschiede.

Ja, da gibt es auch interessante,

also nochmal ein sehr interessanter Unterschied

kommt mit Python 3.3

glaube ich dazu, nämlich die Namespace-Only-Pakete.

Erklär mal.

Die gibt es.

Früher musste man ja immer die InitPUI haben.

Vor allen Dingen deswegen,

damit halt nicht Verzeichnisse,

die halt so heißen wie ein Standardmodul,

das Standardmodul überschreiben.

Und man halt damit dann

quasi öffentlich

sich dazu bekennt, dass das jetzt ein

Paket sein soll.

Also sozusagen, wenn man sich den Infus

schließt, dann muss man das auch wirklich absichtlich gemacht haben.

Und das ist aber

teilweise blöd.

weil oft will man vielleicht auch

Dinge, die in einem Paket liegen, nicht in einem

Verzeichnis haben zum Beispiel.

Und also wenn es

ein InitPy gibt, dann

ist das

ja dann, jetzt weiß ich

nicht mehr die Stelle, wo das irgendwo drin steht,

dass da drin gesucht werden soll, also

Dispass, ja, aber es gibt auch noch irgendwie

andere Stellen, glaube ich. Es gibt auch noch Module,

die nicht da drin sind, zum Beispiel die

Standardbibliotheksmodule

sind, also es gibt welche, die sind irgendwie in

das Python-Binary reinkompiliert und dann gibt es

auch noch welche, die sind irgendwie

woanders hingemarschelt, aber die liegen da auch irgendwo rum.

Also die Python-Module,

die nicht zählen.

Das stimmt, das kann man, aber es gibt auch noch

Dinge, Module, die sind halt einfach nur

in der Shared Library

und nicht irgendwie Python.

Aber da kommen wir gleich noch so,

wo der Pycache und so weiter noch was, aber egal.

Genau.

Aber man kann halt auch,

es gibt auch Verzeichnisse und denen wird

auch gesucht, wenn da kein NPY ist,

das ist allerdings dann irgendwie

weiter hinten.

Und alle, die den gleichen Namen haben,

wenn da jetzt Sachen drin liegen, dann wird das

zum gleichen Paket

gehörig irgendwie aufgefasst

und das ist dann so ein Namespace-Package.

So ein Namespace-Mengeling.

Und dann kannst du halt auch...

Also wir halten fest, einfach immer eine Init-Pi.

Ja, dann...

Aber so kannst du

halt auch Dinge in einem Paket haben, die in unterschiedlichen

Verzeichnissen liegen, was halt manchmal auch ganz praktisch ist.

Klar.

Ja, okay.

Okay.

Was ist dann, das haben wir gesagt,

Package, es gibt auch ein dann dann Package.

Was steht denn da?

Ist das Current Package?

Genau.

Das ist das aktuelle Paket.

Das ist ein Top-Level-Modul oder sowas, ja?

Ja, oh Gott, ich weiß auch nicht.

Ich glaube, wenn es None ist, dann ist es ein Skript.

Also vielleicht noch mal zu distinguieren,

ist das ein Modul, ein Paket oder so?

Wenn Package None ist, dann ist das nur ein Skript.

Und wenn er sucht, dann auch, wer so ein Package findet.

Und wenn er eins findet, dann ist das Top-Level-Modul,

von dem man dann importieren kann oder so.

Und wenn es das nicht gibt, dann gibt es halt auch

Fehler. Attempted Relative Import

Beyond Top Level Package.

Ja, das ist

so eine Sache, die gibt es.

Passiert mir auch

regelmäßig. Echt, das passiert mir nie, das ist

voll seltsam. Doch, passiert mir auch. Es gibt so Sachen, die

machen Menschen offensichtlich

unterschiedlich und das ist so eine Sache, die mache ich offenbar nicht.

Also nicht, weil ich besser bin oder

weil ich irgendwie das toller kann oder so, sondern

weil es einfach was ist, was ich nicht benutze.

Ja gut, aber wenn du relative Importe benutzt, wie du gesagt hast.

Die liebe ich. Relative Importe sind voll gut.

Davon vertippt man sich ja mal.

Also relative Importe, jetzt müssen wir über relative Importe sprechen.

In Python 3

und ich glaube in 2.7 wurde das dann

irgendwann geportet, gibt es die Möglichkeit zu sagen

from .import irgendwas.

Also from .import m.

Oder vom .dot.

Oder auch from .m

import irgendwas.

Und dieser Punkt heißt halt eben immer

aktuelles Verzeichnis.

also aktueller

Pfad.

Das heißt, wenn es in dieser

Installation, die ich habe, zwei Module gibt, die

M heißen, dann kann ich durch

diesen relativen Import genauer sagen,

welches ich meine.

Ach, okay, doch, nee, das war der Unterschied zwischen Modulen

und Packages.

Module haben einen Pfad dran.

Ich glaube tatsächlich, das ist der entscheidende Unterschied.

Ich glaube schon, ja.

Genau, die Top-Level-Package

ist halt irgendwie doch die Sache.

Also wenn man ein Paket finden kann,

also ein Top-Level finden kann mit diesem Dot-Dot,

dann geht das halt. Aber wenn das None ist,

weil man quasi auf der höchsten Ebene ist, dann gibt es halt Fehler zurück.

Und das ist ja genau der Grund, warum...

Das kann natürlich sein, dass ich das einfach nie...

Also für mich ist einfach Punkt, ja.

Wenn ich sage from Punkt importen, dann weiß ich,

das muss im aktuellen Verzeichnis liegen.

Wenn ich sage from Punkt Punkt, dann weiß ich,

das muss im Verzeichnis drüber liegen.

Und für mich ist das einfach eine Möglichkeit,

quasi in meinem Projekt zu navigieren.

Also ich sag mal so, das geht aber nur dann,

wenn der Interpreter richtig aufgelöst ist,

weil wenn du tief drin bist und dann das Skript

beispielsweise manuell ausführt,

relativ tief drin, dann wird der ja diesen Fehler schmeißen.

Wenn du diese Datei direkt

aufrufst. Das kann man übrigens verhindern,

indem man einfach sagt, Python-m

und dann dieses Modul dann innerhalb

von dem Pfad aufrufen.

Die meisten meiner Projekte sind ja bei einem Django-Umfeld.

Und da bin ich nie in der Verlegenheit,

diese Sachen direkt aufzurufen, sondern die werden dann

entweder über einen Run-Server

aufgerufen oder über einen Test oder

über einen Command.

Auch da ist der Pfad, musst du ja

richtig definieren. Ja, aber der Pfad ist

immer festgemacht an der Managed-Py.

Genau. Das heißt, das weiß ich.

Ich weiß, wo der Pfad...

Ja, aber das ist ja auch Python-USM-Package.module oder so.

Genau. Und deshalb ist das vielleicht

was, was einfach in meiner täglichen

Arbeit nicht so auftritt, dass ich da

mich quasi vernavigiere,

weil meine Projekte eben immer

eine feste Wurzel

haben und darunter kann ich

mich bewegen, wie ich möchte.

Ja, mir passiert das halt vor allen Dingen dann,

also einmal, in Paketen

habe ich oft gerne Tests und in anderen

Verzeichnis. Also da gibt es halt Test nicht innerhalb von dem Projekt selber,

sondern liegen halt in einem Test Directory. Wenn da irgendwas nicht richtig konfiguriert ist, dann passiert das halt

schon mal. Und was mir halt auch ab und zu passiert ist,

in Jupyter Notebooks, weil die liegen halt auch wieder in einem anderen Verzeichnis.

Und die sind halt auch irgendwo. Genau. Und deswegen sehe ich das halt

häufiger mal. Bei diesem Import auch ganz interessant. Ich glaube, das kommt dann wirklich darauf an, wenn der Name

des Moduls Punkte enthält oder halt nicht.

weil wenn er Punkte hat, dann

Achso, wenn der Name des Moduls, also wenn das

Modul quasi m.x.y

Genau, dann ist es halt

ein paar Reihenverkehrs

und wenn es halt

wenn es halt keinen Punkt mehr hat

dann muss es eigentlich schon

Top-Level sein, weil dann kannst du nicht

Aber man kann ja jetzt auch so Dinge tun wie

man sagt

from m import

x oder so

und was mit Wings dann. Habt ihr schon mal Skriptnamen mit

Punkten verwendet? Also mit mehreren Punkten drin?

Nee, das hab ich gerade jetzt überlegt, ob ich

eine Datei mit

Punkten drin hätte, ohne also Punkt

Py. Ich glaube, dass das

zu Problemen führt, oder? Ich glaube auch, dass das zu Problemen

führt und das würde ich auch vermeiden einfach.

Ja, interessant.

Stimmt, das hab ich auch noch nicht.

Das müssen wir, das wird dann die nächste

Episode. Was passiert eigentlich, wenn wir Punkt 1

geben? Ja, genau.

Achso, genau, die Form

import m ist ja

noch vergleichsweise offensichtlich. Aber jetzt hat der Jochen eben gesagt,

was ist denn, wenn ich sage, from m import x?

Genau.

Und was dann halt für mich passiert ist,

er importiert erst m

und guckt dann

in m nach, ob es da etwas gibt, was x heißt

und gibt mir das als Import.

Aber das stimmt nicht ganz.

Weil es kann nämlich auch,

man kann auch from m import x machen,

wenn es in m gar kein x gibt.

Weil eben,

wie angekündigt,

wenn m eine

Verzeichnis ist, was eine InitPy enthält.

Dann kriege ich aus dem

Import M alles das raus, was in der InitPy

drin ist. Aber from M

Import X kann dann die Datei X.py sein.

Also M-X.py

und die kann ich mit,

also an die komme ich dran,

aber die ist nicht

in M selbst enthalten. Also wenn ich nur Import M mache,

gibt es nicht M.x.

Kann so sein. Deshalb

ist es dann doch

immer noch ein kleines bisschen

anders. Also man muss eigentlich immer auf die Datei

zeigen, die wir haben.

Ja, genau, das hat mich auch überrascht.

Das wusste ich nicht, wenn man sagt,

import x, ich weiß nicht, was ich vorher gedacht habe,

aber ich dachte, das holt das x da raus

und dann hat man das halt im eigenen Namespace.

Aber eben, es macht halt eher sowas wie import m,

dann sagt es x gleich m.x

und dann sagt es del m.

Und das ist halt eher so das, was tatsächlich passiert.

Und das ist auch schon so, ui, ui, okay.

Also wenn es nicht geht, macht er doch was anderes.

Dann holt er sich doch noch die Detail.

Ja, ja, ja.

Also

es ist natürlich alles übrigens noch gecached.

Man kann so oft import m machen, wie man möchte.

Es wird nur einmal gelesen, die Datei.

Und wo wird das dann reingeschrieben?

In das Dictionary der offenen

Module?

In das Dictionary der geladenen Module.

Das heißt irgendwie sys.modules.

Ja, weiß ich auch nicht.

Keine Ahnung.

Das heißt sys.modules.

Dominik wei es Das ist auch so eine Geschichte das kann man auch sch verwenden Manchmal braucht man ja also Singleton ein ehrlich gesagt

Es hat einen total coolen Namen,

deswegen wollen es die Leute immer verwenden.

Manchmal braucht man das.

Manchmal braucht man es tatsächlich,

meistens eher nicht.

Aber Module sind immer Singletons.

Ganz genau. Und das ist tatsächlich die eleganteste Art,

die ich kenne, wie man das macht.

Und es ist auch manchmal total nervig.

Ja, aber

ich habe da vorher schon

also meistens habe ich dann Borg-Pattern verwendet

oder halt irgendwas in der Richtung

oder manchmal halt auch, wenn ich nicht Borg wollte

sondern direkt Singleton, dann wurde es aber schon hakelig

dann muss man schon

so Meta-Klassen oder sonst irgendwie sowas

so Dinge, wo man sich hinterher schon ein bisschen schmutzig

fühlt, irgendwie machen und

bis ich dann irgendwann mal, weiß ich gar nicht, wo ich das gesehen habe

den Trick, so dass jemand meinte, ja ja, Module sind doch sowieso

Singleton, es sind doch einfach globale Variablen

in einem Modul

Ja, stimmt ja

Stimmt.

Das muss man ja nochmal genau erklären, warum das ein Singleton ist.

Aber Jochen, wenn du dann das Pattern richtig ausführen

musst, musst du dann noch in dem Modul noch ein

Get irgendwas

machen.

Ja, ja.

Falls jemand versucht,

drumherum zu kommen.

Ja, genau. Eigentlich ja.

Jetzt der Dominik

möchte es gerne erklärt haben.

Also ein Singleton macht irgendwie,

dass er guckt, ob es schon ein Objekt gibt,

das dieses Typen ist und gibt das

zurück, wenn es schon gibt, und schert einfach das eine,

was es nur geben darf. Ja, Singleton heißt ja erstmal

nur, es gibt während der Ausführung des

Programms nur eins davon.

Egal, was davon ist.

Und Borg ist, dass es gibt ganz viele davon, aber die sind

alle dieselben Eigenschaften.

Ja, da wird der State

geshared, aber es ist nicht die gleiche Instanz

tatsächlich. Es können unterschiedliche Instanzen

sein, aber der State ist immer der gleiche. Genau, das heißt,

die Eigenschaften sind alle dieselben über alle Instanzen hinweg.

Ja, genau.

Und Singleton kriegt man eben durch

Modul einfach hin. Also ich mache eine Datei

singleton.py

und da schreibe ich rein x gleich 2.

Dann mache ich import singleton

und dann sage ich singleton.x

und das ist jetzt diese

Instanz, dieses .x

gibt es nur genau einmal, weil der

Python Interpreter eben beim Import

jede Datei

nur einmal importiert, um es mal so zu sagen.

Wenn eine Datei einmal importiert wurde,

dann liegt die im Cache und dann

wenn du dann import singleton sagst, kriegst du wieder

die aus dem Cache.

mit allen ihren Eigenschaften.

Das heißt,

du kriegst es mit dem...

Du kannst es nicht ganz

einfach machen, dass du diese Datei nochmal

importierst, weil Python halt sagt,

ja, die kenne ich ja schon. Brauche ich nicht nochmal

importieren.

Weil dieser Import,

was ist das? Ein Modultyp dann,

wenn du ein Modul hast? Genau, das heißt Modul.

Und dieser Modultyp ist einfach

eine Detailkette, keine Ahnung, von dem...

Ja, das Ausgeführte.

Das ist eigentlich der ausgeführte Code, der da drin ist.

so einer Closure, die außen rum...

Aber das wird dann doch gecastet,

was dann Eval wäre, oder das habe ich dann nicht genau...

Ja, im Endeffekt macht es ein Eval,

aber halt ein

sehr gut verstecktes.

Ja gut, ich meine,

Import heißt, führ mal bitte den Code

in der Datei XYZ aus, also

musst du ihn irgendwie ausführen. Irgendwo muss da ein Eval

drin sein.

Aber es ist eben hinter so vielen Schichten

versteckt, dass du es nicht siehst. Also was der macht, ist,

er lädt diese Datei... Immer wieder und immer wieder.

Das heißt, wenn ich auch von mehreren...

letzte einmal. Aber wenn ich an mehreren Stellen das habe,

was ist denn dann passiert?

Beim ersten Import Singleton wird diese

Datei geladen und ausgeführt und

das Ergebnis dieser Ausführung wird als

Module Singleton

abgelegt in diesem SysModulesCache.

Und vielleicht wird dann da PyCache

rausgebracht, PyC-Files oder so?

Ja, nee, das ist nur eine interne

Repräsentation. Das ist halt eben ein

internes, das ist eine Klasse, die heißt

Module und die hat Eigenschaften.

Ja.

Und wenn du dann nochmal Import Singleton

machst, zum Beispiel in einer Datei oder

zu einem späteren Zeitpunkt oder in einer Schleife, wo du es

tausendmal machst, dann wird

nicht nochmal diese Datei singleton.py

geladen, sondern dann guckt er eben in seinen

Sysmodules Cache und sagt, ah ja, den Namen singleton kenne ich schon.

Genau, also beim ersten Import

lädt er das tatsächlich in den Pycify

rein, also das heißt, er macht aus Bytecode draus,

er komponiert das quasi und

er liest das quasi einmal aus,

und man kippt das aus,

macht dann Bytecode draus und dann schreibt er das

in Pycache rein und von da versucht er dann

erstmal zu laden aus Pyc.

Genau.

und dann ist dieser Code nicht mehr da.

Es ist nur noch das Ergebnis da.

Das Ergebnis der Ausführung dieser Datei

ist dann das, was in das Modul reicht.

Und was wird dann in die PyC-File reingeschrieben?

Die PyC-Files sind so eine

zwischendurch Optimierung, weil

die

enthalten so einen vorkompilierten Bytecode

und der ist schneller zu laden als eine

.py-Datei. Und das ist ein

Marschalt-Objekt. Also wir hatten die ganz am Anfang

einmal kurz Marschalt gesagt. Was ist das überhaupt?

Einmal kurz nochmal den kleinen Exkurs.

Jochen, erklär du doch mal.

Ach ja, damals. Genau, im Grunde Marschaling ist eigentlich ein anderes Wort oder ist eines der Worte, die man benutzt, wenn man jetzt zum Beispiel Code oder irgendwie eine Datenstruktur serialisieren möchte in eine Liste von Buchstaben oder in einen String oder in eine Byte-Datenstruktur, die man dann halt irgendwie auf einer Platte speichern kann oder mit sich rumtragen.

und genau, und da gab es zwei Module, die ersten waren halt Marshall,

das heißt auch so, das gibt es immer noch in der Standardbibliothek,

und Shelf, Shelf war schon damals nicht so richtig populär,

also Marshall kann man immer noch verwenden, kann halt nur relativ wenige Datentypen

und in neueren Python-Versionen verwendet man da eigentlich immer Pickle für,

aber das ist halt im Grunde das, was es macht, wenn man sagt,

vom Pickle, oder wenn man sagt cpickle.dump, dump-s oder so,

dann wird das halt in String oder dump in einen Teil geschrieben

und dann hat man halt eine in einem String

serialisierte Form von zum Beispiel irgendwie

Code. Also mittlerweile nutzt man glaube ich sogar

Dill oder sowas, ne?

Dill as Pickle oder so,

als neue Version. Ja. Als Third-Party-Package

irgendwie, ja. Schön, schön.

Können wir auch machen. Okay, aber ein Marschall-Objekt,

falls ihr das irgendwo findet, ist quasi eine serialisierte

Form von

dem, wie es heißt, Code, der da

gelaufen ist, ja. Genau.

Okay, jetzt haben wir aber, okay, jetzt haben wir es irgendwo geladen,

haben wir es gefunden. Was importiert ihr dann?

Was ruft ihr dann auf? Ja, das

Ergebnis dieser Ausführung.

Also import.dot, dann dann import.

Dann dann.

In diese Funktion kommen

dann halt die Argumente rein, die

Ja, das kann ja alles möglich sein.

Da kannst du auch beliebige Objekte

in der Datei reinschreiben.

Kannst auch ein Modul machen, was einfach nur einen String enthält,

wo irgendwelche Binärdaten drin sind.

Macht man ja manchmal,

weil man Testdaten braucht.

Das Modul hast, wo einfach

so ein paar Strings drin sind. Und wenn die

eben ausgeführt werden, dann werden die halt so einer

String-Objekt in Python

mit einem Namen und genau diese

Sachen, also im Endeffekt ist das halt so

ein Dictionary, was da drin ist, so ein Unterstrich, Unterstrich,

Dikt, Unterstrich, Unterstrich.

Das hat natürlich noch mehr so Attribute, ja.

Der Path ist da drin

und der ursprüngliche

Importname und der Docstring

wird rausgelesen und so weiter. Also diese ganzen

Sachen, die halt so passieren, wenn Python was

ausführt,

die passieren da auch. Alles das, was Python langsam

macht. Alles das, was Python awesome

macht.

Genau, und das Ergebnis dieser Ausführung ist halt dann das, was das Modul ist.

Das zusammengefasste Modul. Da gibt es Modul.doc und Modul.tikt und Modul.

was weiß ich noch alles, .name und .path und .package

Genau, also alle diese Sachen, die halt dazu gehören. Aber das ist dann schon ein Python-Objekt.

Also es ist keine Datei mehr, sondern es ist dann ein fertiges Python-Objekt.

Und auch diese Klassen, die müssen ja erzeugt werden

und wenn es so Meta-Klassen hat, dann müssen die ausgeführt werden. Also alles das, was da

wenn man die Datei in den Interpreter eingibt

und dann alles was da rauskommt

eben zusammenfasst

in eine Sache gepackt

also es ist eigentlich von der Organisationsebene her

finde ich sehr sauber

weil alles was in der Datei drin ist

ist dann eben als Python Objekt verfügbar

und das ist auch für mich so ein bisschen

der Grund warum man das braucht

dass ich halt einfach bestimmte Python Objekte

oder bestimmte Dinge in andere Dateien

reinschreiben möchte

und diese Dateien sollen in anderen Verzeichnissen liegen,

damit ich nicht die Übersicht verliere.

Und ja.

So, das ist Import.

Und jetzt

gibt es noch Importlib.

Ja, das wird ja

aufgerufen sogar, also Import wird ja Import,

auch wenn man es nicht überschrieben hat.

Import ist eigentlich syntaktisch, genau, das kommt ja

auch noch dazu, das ist ja in dem Artikel

glaube ich nicht drin, aber in der Diskussion war es dann drin,

man kann das auch überschreiben, man kann auch

selber eingreifen in den Importprozess.

also Dinge, die man

auf der Liste der Dinge, die man unbedingt tun sollte

ist das ganz, ganz

weit unten

Es gibt

Importlib und in Python 3 irgendwas

hat auch

dieser Importprozess ist quasi

zu einer Python-Funktionalität geworden

den man programmatisch

aufrufen kann, was sehr nützlich ist

und

diese Statement

Import M ist quasi nur noch

ein syntaktischer Zucker für

importlib.

.import

Ja, irgendwie sowas.

Das

coole daran ist, dass man

eben jetzt in diesen Prozess eingreifen kann.

Und das ist insbesondere dann für zwei Sachen nützlich.

Die erste Sache, für die es super nützlich ist,

da muss ich jetzt leider auf meine eigenen

Dinge verweisen, da werde ich

in Kürze ein Video dazu hochladen.

kommt dann natürlich in die Show.

Wenn man etwas

neu laden möchte,

weil

wir haben ja eben besprochen, wenn ich Import M

mache, dann wird es einmal geladen

und dann nie wieder.

Man ist ja jetzt oft als Softwareentwickler in so einer Situation,

dass man Dateien dann verändert und die

eigentlich sofort

haben möchte, ohne dass man das Programm

neu startet. Und um das hinzukriegen,

habe ich mir halt so ein bisschen

einen Glue-Code geschrieben, der Dateien

überwacht und wenn die sich ändern, dann wird da halt

Reimport durchgeführt.

Und das ist möglich durch die Funktion

aus Importlib. Da kann ich sagen,

importiere diese spezifische Datei,

auch wenn

die schon mal importiert war,

und dann

wird die importiert. Egal, ob die schon im

Cache liegt oder nicht. Ja, cool. Ja, ich meine,

der Entwicklungshelfer von Junkmo,

der kann sowas ja auch. Ja, aber der macht ja

einen Neustart. Der macht tatsächlich einen Neustart, naja.

Der hat so einen Watcher-Prozess und dann

schießt er einfach den Prozess ab und startet einmal neu.

Ach so, ich weiß gar nicht, wie das

gut, das ist ja, oh mein Gott, das ist ja schrecklich.

Ja, aber es hat auch Vorteile,

weil dann halt alles

auf Null zurück ist.

Wie ist das denn bei

Jupyter, ist das ja auch so, da kann ich ja auch beim

Import sagen, ob ich das jetzt möchte,

dass ich das nochmal importieren will,

wenn es sich ändert. Ja, dann mach doch ein Reimport.

Da gibt es eben diese Jupyter Magic,

die du sagen kannst, und der benutzt

tatsächlich Import-Lib und macht Reimport.

Aha, okay.

Neustarten wäre auch blöd.

an der Stelle.

Geht ja auch an der Stelle einfach gar nicht.

Zum einen, weil der Prozess ja da

läuft und zum anderen, weil

der die anderen Zellen nicht kaputt machen will.

Das heißt ja, die Zellen immer noch.

Ich hatte übrigens tatsächlich jetzt

letzte,

vorletzte, nee, letzte oder vorletzte, nee, glaube letzte

Woche, und ich erinnere mich schon nicht mehr dran,

den Fall, wo ich tatsächlich Importlib gebraucht

habe und habe halt die Importfunktion

überschrieben.

Was hast du damit gemacht?

für einen, ich habe einen

Pull-Request bei Wagtail Media

eingereicht, weil

es nicht mit Wagtail 2.13 kompatibel war.

Und da gibt es Tests

und das Problem ist jetzt,

man möchte die Tests

ja, also da ist

dann, okay, ich fange einfach mal von der Seite

an, es gibt im Code so Dinge wie

probier das mal zu importieren,

wenn es schief geht, mach was anderes, weil

zum Beispiel diese Telepath

Bibliothek gibt es erst ab Worktel

2013.

Und da sagt man halt, probiere es zu importieren.

Ja, auch für lokale, ich benutze es ganz häufig für lokale

Settings, ja. Irgendwo eine local settings.py

und dann macht man halt

try import local settings.py

und accept pass.

Ja. Genau, genau.

Und jetzt müsste man das aber testen.

Jetzt möchte man testen, dass wenn

und es gibt da noch kompliziertere,

wie gesagt, das habe ich jetzt wieder vergessen, blöderweise, ein bisschen kompliziertere

Logik, die davon abhängt, ob man es jetzt geschafft

hat, das zu importieren oder nicht.

und jetzt, wie willst du das testen, ob jetzt wirklich der richtige Code ausgeführt wird, also der Code, der zum Beispiel dann nur so ein Dummy-Objekt anlegt,

wie willst du testen, ob das funktioniert hat, wenn du nicht dann noch eine andere Paketversion installieren willst, was du im Test auch nicht gut machen kannst?

Ja, und dann habe ich da einfach quasi Import-Funktionen überschrieben und dann in der Import-Funktion gucke ich halt so, wird gerade versucht, das da zu importieren?

Ja, wirklich? Gut. Race-Exception, ja, und dann Race-Import-Error.

und dann kann man halt testen, okay, und ist jetzt wirklich das Sammely-Objekt, ja oder nein?

Und dann hat man einen Test dafür.

Ja, aber fand ich spannend.

Das ist auch ganz schön tief eingegriffen.

Ach, der Jochen auch aufgenommen?

Ja, genau.

Du musst jetzt aber suchen, in welcher Folge das war.

Kannst du uns da einen Link geben, Jochen?

Kann ich auch mal in die Schauenden folgen.

Das ist ja cool.

Ja.

Ja, was kann denn noch alles dann passieren?

Genau, das ist jetzt sozusagen, der Jochen hat jetzt hier schon die Brücke zu dem zweiten Anwendungsfall geschlagen,

was dann eben hier aus diesem Artikel in der Diskussion

rauskam, man kann auch

im Importsystem was anderes

machen

und der schöne Vorschlag, der da kam

beziehungsweise das schöne Beispiel, was da in

dieser Diskussion kam, ist

dass man ja prinzipiell auch andere Sprachen

integrieren könnte. Einfach Importsystem auf einen ansetzen

Das kann man auch machen, dann ist man in

seiner eigenen Welt

aber quasi das Gegenteil

davon ist, wenn kein Python-Modul

gefunden wird, dann kann man ja mal schauen, ob man irgendwas anderes

kompilieren kann, was diesen Namen hat

und wenn das

kompilierbar ist und kompiliert, dann einfach das

importieren. Und es hat wohl jemand

geschrieben, dass jemand sich eben so Lisp-Dateien

rein importieren kann, die

live kompiliert werden, wenn man

sie importiert.

Reichlich abgefahren, würde ich sagen

und ich empfehle auch niemandem, diesen

Weg zu gehen, aber es ist

schön, dass es jemanden gibt, der das

gemacht hat und das möglich ist.

Ich wüsste

jetzt tatsächlich keinen richtig sinnvollen

Anwendungszweck davon, aber

Ja.

Irgendwann wird es

einen Anwendungsfall geben.

Ich habe gerade überlegt,

wenn man das jetzt mit TypeScript macht,

man möchte auf dem Backend

und vorne den gleichen Code.

Ja, und dann wird es noch

mit dem JavaScript to Python

Compiler noch Python gemacht.

Dann hat man noch einen Server,

was WebAssembly kann.

Man kann Python schreiben für Frontend.

Und schon

eigenes, die eigene, deine Dateien bestehen quasi nur noch aus Import Statements. Alles mit Import Statements gemacht. Ja, das ist so wie der Präprozessor, der ist auch Turing vollständig.

Ja, tja.

Da hat jemand super wieder sein...

Vorhin haben wir noch drüber gesprochen, ob wir unser Telefon ausschalten wollen.

Flugmodus gestellt, aber nicht

mein Rechner.

Auf meinem Telefon hat es auch nicht geklingelt, sondern

mein Rechner kann halt auch dummerweise klingeln.

Was kann denn noch alles schief gehen bei den

Importen? Ja, eigentlich kann beim Importen alles

schief gehen, oder? Das ist ja...

Ja. Da steht irgendwas

komisches drin, also keine Binärcodes oder irgendein andere

Zeichen, das er nicht lesen kann oder sowas.

Ja, es kann auch...

Ich glaube, das Schwierigste an diesem Importsystem

ist, dass es halt manchmal überraschend ist.

Dass es einem Sachen versucht zu importieren,

die man nicht gemeint hat.

weil die Reihenfolge im Path falsch ist

oder weil da Module liegen, die man noch nicht kennt

oder weil man versehentlich

einen Namen verwendet hat, den es schon gibt.

Also wenn man so eine Kette durchgeht,

also man möchte jetzt A importieren und A

möchte aber jetzt C, D, E, F, G und

Genau, sowas kann natürlich auch passieren, dann hast du zirkuläre

Imports, das ist auch schlecht.

Ja, aber das wäre ja von A von B und B von C

und C von A. Ja genau,

und das hat man ja manchmal.

Aber das war ein anderes Problem, als das ich gerade meinte.

Das ist also ganz, ganz, ganz viel Zeug.

importiert. Also du könntest ja quasi eine Sache importieren, der importiert

alles andere, die ganze Standard-Python.

Im Prinzip machst du das ja so in deinem Skript.

Das ist halt so relativ getarnt,

was da passiert. Man macht relativ viel

Magie schon.

Die komplizierte

Frage wäre, ob das das dann doch langsam macht,

wenn man sowas raussucht und sagt,

beim ersten Mal schon. Das heißt, da kann der Starten

relativ lange dauern und beim zweiten Mal

vielleicht nicht. Aber es gab irgendwie

so ein Problem, dass irgendwer hatte, der das

mal ausprobiert hat wegen den Imports.

immer wieder. Ja, ja, ja. Also das Problem

gibt es halt, wenn du halt irgendwie so auf die Richtung

weiß ich nicht, Millionenzeilen

Python oder so zugehst, dass eben dann, wenn das

zum Beispiel im Entwicklungsserver, wenn der neu startet,

wenn du änderst irgendwas, dann startet der neu

und dann dauert das halt eine Minute.

Das ist halt schlecht. Das ist halt immer so richtig

flüssig beim Entwickeln. Es hieß ja

irgendwie so, ne, wir haben das Google, aber ich glaube,

das war bei Instagram das Problem oder so.

Ja, bei Instagram gibt es auch bei

Eventbrite gibt es das, glaube ich, auch.

Ja, die sind nicht so groß wie Google.

Ja, aber die haben, glaube ich, auch irgendwie

oder

verwechsel ich das gerade?

Ich meine, es ist Eventbrite, aber auch ungefähr eine Million

Zahlencode und Instagram halt auch

vielleicht noch mehr, weiß ich.

Ja, okay. Aber das ist ja dann so

ein...

Das Problem ist ja eigentlich, dass halt die Sachen

erst so in Anführungszeichen kompiliert werden,

wenn ich Import sage.

Und deshalb haben andere Sprachen das nicht, weil die

machen das halt einmal vorher.

Aber so eine richtig gute Lösung,

also ich meine, es gibt PyO-Dateien

und PyC-Dateien,

die sind ja wohl schneller

ja

oder könnte man

sowas auch marscheln

könnte man Imports durchführen

und das dann, ja im Prinzip schon oder

wahrscheinlich schon ja

einfach mal alles gepickelt

ja

ach deswegen auch weil der Pickel ist die Haube von dem Marschall

jetzt verstehe ich das auch

ich dachte Pickel ist so ein Einmachglas

Marschalls haben doch so eine Pickelhaube auf

ja, also dann passt das auf jeden Fall

zusammen

Das ist doch zumindest schon irgendwie

Sorry, weigert es

Das Englische, wo Pickels heißt, eingemacht ist

Ja, ja

Ich glaube, das ist die

Okay, aber zirkuläre Importe wollte ich nochmal

Ja, zirkuläre Importe sind auch eine schöne Sache

Also man kann ja sowas machen wie in Python

Form A, Import B und dann

B machen, Form B, Import irgendwas

oder Import A, Import B, Import D und so

und das funktioniert einfach, aber erst wenn man es dann ausführt

dann nicht mehr, weil er dann darauf zugreift

und dann sagt, das kennt er noch nicht

Genau, beziehungsweise ist schon geladen

oder ist schon am Laden.

Also wenn ich

zirkuläre Verweise

habe, vom A Import B und in B

sage ich vom, wenn ich

Modul A und B habe und in A

sage ich Import B und in B sage ich Import A,

dann kann ich die beide nicht importieren, weil zu dem

Zeitpunkt müsste ich sie beide gleichzeitig

importieren und das geht nicht.

Und da kann ich natürlich beliebig

viele dazwischen schieben. Ich kann A, B,

C, D, E, S. Solange dieser

Kreis sich irgendwann schließt,

ist schlecht.

Also es fällt ja direkt auf. Ich glaube, wenn man drei hat,

dann fällt es glaube ich nicht immer direkt auf.

Wenn man vier oder fünf hat, dann fällt es erst recht.

Das siehst du dann beim

Importieren. Und wie löst man das denn, wenn man

so ein Problem hat?

Laufzeit-Imports.

Also lazy quasi.

Das ist doch das, was man in so

Salary-Tasks immer machen muss.

Weil diese Tasks können von irgendwo her

gestartet werden und die sollen dann irgendwas machen.

Und die müssen

ja auch irgendwie diese Modelle importieren, aber das Modell

selber m Also das ist so mein klassischer anwendungsweise Ich m dem Modell sagen ich muss hier Werte nachberechnen ich muss hier ein PDF erzeugen und das dauert lange und deshalb mache ich

das in dem Task. Aber dieser Task soll ja dann wieder

dieses ursprüngliche Modell speichern.

Das heißt, ich kann in der Tasks-Datei

nicht das Modell importieren,

weil das Modell hat schon den Task importiert.

Und deshalb ist das so ein

Pattern, wenn man Celery-Tasks schreibt,

dass diese Tasks

zur Laufzeit alles importieren. Also

in der Datei, in der Funktion

dev compute pdf.

Da habe ich erst mal ein paar

Importzeilen drin. Import from models

import irgendwas.

Import pdf generator.

Und noch alles, was man da halt so importiert

braucht. Und dann werden diese

Imports erst ausgeführt, wenn die

Funktion gestartet wird. Also von mir, von meinem

geistigen Auge, die ich mir gerade so ein paar Tickets ziehe.

Die To-Do-Listen müssen ja an.

Genau.

Das bedeutet halt, dass dieser Import nicht

ausgeführt wird, wenn die Datei geladen wird.

Was eben der

Fall wäre, wenn es oben in der Datei drinstehende,

sondern dieser Import wird erst ausgeführt,

wenn die Funktion, die da drin ist, gestartet wird.

Weil quasi nur der

Funktionsname geladen wird und das, was

passieren soll quasi. Genau, richtig.

Und wenn ich diese Funktion dann ausführe,

dann wird dieses Import Statement ausgeführt.

Und dann sind die anderen Sachen schon da

und dann hat man quasi den Laser Import, dann kann man

das dann wieder machen, weil die sind ja schon...

Das ist dann schon fertig, importiere diese Models, die sind schon im Cache,

dann kann ich einfach in den Cache zeigen und sagen, hier gibt man das.

Bin also

sozusagen aus diesem Prozess raus.

und das ist auch sowas, was eben

anders ist als in anderen Sprachen.

Import ist ein Statement, was einen Effekt hat.

In C, wenn ich

in C sage, import header.h,

dann hat es keinen Effekt,

das ist kein Code, der da erzeugt wird.

Punkt H ist immer Header,

noch mal für alle Leute kein C.

Punkt H ist immer Header, das sind so die

Definitionen, die Deklarationen,

nicht die Definitionen, die Deklarationen, was es da gibt

und die Punkt C Datei enthält

dann die Definitionen normalerweise.

Also Header.h ist natürlich die Definition der Header.

Die Definition,

da muss ich dann eine

Datei dazugeben, die heißt

Header.c

War nur ein Beispiel.

Aber

dieses Import-Statement in einem c,

das wird vom Compiler ausgeführt, das wird nicht

zur Laufzeit ausgeführt.

Und in Python ist das anders.

Der Compiler, der macht das,

der schneidet die einfach zusammen, alle zu einer großen Datei

und dann liest der einfach von oben nach unten.

und dann gibt es noch den Linker, der dann dafür

sorgt, dass diese Verweise alle an der korrekten Stelle

in die korrekte Stelle zeigen. Das ist so ein

mehrstufiger Prozess und es ist halt alles

bevor das Programm gestartet wird.

Und in Python ist immer alles

nachdem das Programm gestartet wird.

Und das ist halt hier genau das Problem. Wenn ich

Import B sage und

versuche aber schon was zu importieren

oder versuche schon B zu importieren,

dann geht es halt nicht.

Weil das dann eben so einen Kreis

bildet, der nicht aufgelöst werden kann.

Wenn ich das aber erst später im Programm sage,

wenn ich irgendwelche Funktionen geladen habe,

die dann später nochmal

diese Module brauchen.

Ist egal, wo die herkommen.

Wenn die schon im Cache sind, einwandfrei.

Okay, aber das widerspricht ja so ein bisschen dieser

Philosophie, dass Importe immer ganz oben stehen.

Ja, genau. Deshalb ist das hier so der

Nachteil da dran.

Ja, ich fühle mich da auch immer so ein bisschen schmutzig, aber

ja, ich mache das auch so. Aber es ist halt das Pattern

und das ist der beste Weg außenrum.

Es gibt noch eine andere Möglichkeit,

die ich auch

niemandem empfehlen möchte. Es ist ein sehr schöner Hack,

den ich mal gehört habe.

Wenn ich jetzt zum Beispiel nur einen Task importieren möchte,

dann sage ich from tasks import

greatpdf.

Und der Importprozess führt

tatsächlich nur so lange diesen Import

aus, bis dieses Objekt vorhanden ist.

Alles was unterhalb dieses Objektes ist,

wird

nicht ausgeführt.

Das heißt, wenn ich meine Importstatements

ans Ende einer Datei mache,

dann kann ich zirkuläre Importe

machen,

in bestimmten Situationen, dann geht

das.

Aber

das, wie gesagt, ist keine

Empfehlung. Es ist nur

Imports ans Ende der Datei schreiben ist

schon generell schlecht, weil man sie dann nicht mehr sieht

und es ist auch dann schlecht, wenn man dann

zirkuläre Importe... Das kann man dann wahrscheinlich auch noch

ein bisschen verschachteln oder so. Also alle Leute, die

ein größeres Interesse

an Job Security haben, jetzt mal

aufpassen mit Schreiben.

Das kriegt man hinterher nie wieder aus

und wenn man dann noch

Homoglyphen nimmt und die Dateien

alle gleich ausschauen, dann

hat man ganz gewonnen.

Ja, das ist ein Hack, der

die Interna missbraucht, würde ich nicht empfehlen,

aber es ist schön, dass es das gibt.

Ja,

ist auch manchmal interessant

zu wissen, warum irgendwas funktioniert, wo man

denkt, das kann gar nicht funktionieren, aber es funktioniert

dann doch.

Ja, ja.

Nicht so selten, wie es funktioniert, was nicht, was eigentlich funktionieren sollte, aber trotzdem auch.

Leider.

Ja.

Ja, Imports haben wir, oder?

Ja.

Erklärt, oder fällt euch noch was ein?

Bin mir sicher, dass da noch ganz viele Fragen kommen.

Vor allem, wie funktionieren Imports in anderen Sprachen?

Ja, anders.

Ja, das nicht so genau.

Ich bin mir sicher, dass da ganz, ganz, ganz viele Fragen noch offen sind und dass da ganz, ganz, ganz viele Fragen noch kommen werden.

aber so. Ich glaube, den...

Ein bisschen als Einstieg, weil, also ich meine auch,

mir waren da viele Dinge

nicht so richtig klar. Also jetzt, nachdem ich den Artikel

zumindest teilweise so gelesen habe,

dachte ich, ja, okay, da kann man schon coole Sachen mitmachen

und vor allen Dingen kann man das auch,

dass das eben, dass ein Modul auch nur einfach

ein Objekt ist, das ist irgendwie die Eigenschaft,

kann man ja eigentlich total gut ausnutzen, um damit

irgendwie Dinge zu machen.

Aber sollte man.

Sollte man vielleicht nicht, aber,

also zum Beispiel ein tatsächliches Problem,

wo ich halt auch schon so mit Paketen

und Dingen rumgespielt habe, wo ich dachte so,

oh, da gibt es, irgendwie gibt es da keine gute Lösung

für, aber es wäre schön,

eine zu haben, ist halt, oder ich weiß nicht, vielleicht kennst du

eine, ich meine, im Machine Learning-Bereich,

wenn man da Modelle hat, man trainiert die Modelle

jetzt aber nicht, also man hat normalerweise ein

Produktionssystem, was irgendwie dann Dinge

tut, so mit echten Usern und

echten Daten und so,

aber da

entwickelt man ja nicht und man trainiert ja auch nicht

die Modelle, sondern Modelle trainierst du dann meistens irgendwie

in einem Jupyter-Notebook oder so,

dann hast du da dein Modell

und jetzt willst du das irgendwie

aber in deine Produktionsumgebung integrieren.

Wie machst du das denn? Jetzt kannst du

natürlich jedes Mal, wenn du dein Modell trainiert hast,

aber das sind ja oft Dinge, die dann auch periodisch passieren

und automatisch, kannst du

ein neues Paket bauen und das dann releasen.

Aber dieser Deployment-Prozess

ist halt ziemlich invasiv.

Vielleicht willst du

das nicht regelmäßig oder auch nicht automatisch

machen, weil du brauchst Verbrechtigungen

auf irgendwelchen Systemen und keine Ahnung.

Gut, kannst du das natürlich auch, kannst du irgendwie

Deployment automatisieren, was halt so ein bisschen höhe ist.

Und du hast dann ganz, ganz

viele Paketversionen auch

und es ist halt viel,

diese Modelle sind halt teilweise sehr riesig.

Also irgendwie

ist das nicht so richtig schön und

das ist halt die Frage, wie macht man das eigentlich ordentlich?

Und du hast das Problem, wenn man jetzt Sachen pickles,

zum Beispiel auch,

dann ist das

von dem Python-Interpreter abhängig

und so

und der ist möglicherweise in diesem

Jupyter-Notebook-Umfeld, wo jetzt

Data Sciences, irgendwelche Modelle trainieren, halt auch wieder

anders, aus speziellen Gründen anders

als in der

Produktionsumgebung, wo dann die...

Und Pickel kann ja selbst auch Imports durchführen.

Ja.

Du musst ein bisschen aufpassen, wenn man

Versionen nimmt oder so, also Sachen pickelt und dann

Python-Versionen weitergeht, dann geht

das dann mal kaputt, das heißt, das ist nicht mal so einfach

dann... Ja, beziehungsweise auch, wenn du andere Imports

hast oder andere Versionen, Pickel

importiert halt die Sachen, die es braucht und

ja.

Ja, und also das ist

Das kann schon, also da gibt es

diverse Fallstricke und der Weg, den ich dann

irgendwann gegangen bin, ist halt dynamisch

Conda-Pakete zu bauen und weil das

mit Conda relativ leicht ging, aber das war

da kann, ich weiß nicht, ob es da Importlib, doch

Importlib gab es glaube ich auch schon, ich wusste aber nicht so viel

davon, ich weiß nicht genau

und die habe ich dann halt sozusagen als

Django-Modelle

irgendwie als Files irgendwo hingelegt und dann

diese Pakete importiert und dann konnte man einfach

einfach sozusagen sich, konnte man

in einem Jupyter-Notepunkt, wenn man ein Modell fertig trainiert hat

konnte man sagen, deploy mir dieses Modell irgendwie

und dann tauchte das halt auf

und wenn man es ausgewählt hat, wurde es halt importiert.

Und zwar einfach aus...

Aus der Datenbank importiert.

Aus der Datenbank, beziehungsweise nicht aus der Datenbank, sondern

aus der Datenbank plus irgendwie,

naja, nicht in dem Filesystem, sondern in der Filesystemabstraktion

im

Files storage,

und

das geht wahrscheinlich auch

ohne Conda, nehme ich mal an,

wenn ich das jetzt mir so überlege.

Und wahrscheinlich geht das auch noch eleganter,

als wie ich das damals gemacht habe.

Ja, aber also jetzt mal die Diskussionsfrage, warum nicht wirklich aus der Datenbank importieren? Im Prinzip sind da nur irgendwelche Daten, kannst du da als String da reinlegen und kannst sagen, importiere mir dieses Modell, kannst du ein Reimport machen und dann wirst du vermutlich noch so einen Proxy-Pattern brauchen.

Ja, also das Ding für

Conda war dann halt tatsächlich

irgendwie, was ist, wenn ich jetzt irgendeine spezielle

Abhängigkeit habe

in meinem Modell, also ich benutze jetzt irgendeine

neue fancy Maschine

in der Bibliothek, die ich auf dem

Produktionssystem jetzt aber noch nicht habe

Ja, okay, dann stirbt es ab und

Genau, und dann ist halt

kaputt, wie kriege ich das

da mit rein und zwar ohne, dass ich

ja, und das war, über Conda ging das

aber

Ja, okay.

Das ist natürlich schwierig, vor allem wenn du dann Sachen installieren

musst, die du eigentlich, was du an der

Stelle eigentlich nicht willst. Wobei,

also ich meine, Pip gibt es auch als Bibliothek.

Du kannst auch Pip aufrufen

von Python heraus.

Also,

was ich für

meine

interaktive Programmierungssache gemacht habe, ist

eben so ein Proxy-Pattern.

Dass du quasi

eine Schicht dazwischen hast.

weil du möchtest ja

an der Stelle, wenn du es neu importierst,

musst du halt auch ganz viele Instanzen ersetzen.

Eigentlich. Und das ist

schwierig, weil die hast du oft nicht selber in der Hand

oder da kommst du oft einfach gar nicht dran.

Also Instanzen, das heißt, du musst die laden mit dem neuen Kontext

der neuen Importe. Genau, weil

du den neuen Code hast und eigentlich

müsstest du jetzt die... Du musst aber dann quasi ja alle

Transaktionen, die du auf der einen Instanz hast, schon gemacht hast,

schon wieder nachvollziehen, weil du den State ja quasi wiederherstellen musst.

Genau, also genau, das ist die eine Sache,

du müsstest den State quasi wiederherstellen und die andere

Sache ist, du müsstest den Code ersetzen, weil

Ich habe jetzt ja ein m.x und ich möchte aber ein m.x2 haben.

Aber das kann jetzt ganz anders sein, weil du hast jetzt nur m.

Ja, genau, kann sein.

Und dafür gibt es einen Pattern, das heißt Proxy-Pattern,

wo du quasi ein Interface definierst, was da alles drin ist.

Was ist denn ein Interface?

Also du definierst quasi, was ein Objekt kann.

Also ein Typ.

Und die eigentliche Umsetzung ist aber quasi eine Klasse dahinter.

Du definierst quasi den Typ und dann...

Dieser Proxy macht nichts anderes, als diese Aufrufe weitergeben.

und dann kannst du nämlich dem Proxy sagen, ersetz mal deinen Background,

ersetz mal deinen Hintergrund, den Code, ohne den Proxy selbst anfassen zu müssen,

den du halt oft nicht rauskriegst, weil der in irgendwelchen Sachen drin hängt.

Und ich könnte mir durchaus vorstellen, dass das mit so Machine Learning Modellen auch funktionieren könnte,

dass du halt einen Proxy hast, der dieses Modell weg abstrahiert und der kann die Sachen irgendwoher wiederladen,

ob das jetzt aus der Datenbank ist oder aus dem Dateisystem oder sonst woher.

einfach, dass du eine Trennungsschicht drin hast.

Ja, das ist wahrscheinlich auch

der richtige Weg.

Das wäre der richtige Weg.

Ja gut, man weiß das ja

oft zu dem Zeitpunkt nicht so richtig.

Es ist einiges an Verwaltungsaufwand,

so ein Proxy richtig zu machen und

das geht in manchen Sprachen einfacher.

Ein Interface definieren geht

in Java ganz einfach, weil das gibt es da halt.

In Python ist es halt nur eine Klasse,

die lauter Not Implemented Errors hat.

Ja, aber ungefähr so, ja.

Ja.

Ja.

Achso, gibt es zu diesem Projekt, gibt es da eigentlich auch schon einen Link oder sowas?

Nee, demnächst.

Demnächst.

Wird nachgereicht.

Ich liefere das nach.

Okay.

Und jetzt habe ich es öffentlich gesagt, jetzt muss ich es auch wirklich machen.

Das ist immer gut.

Sehr schön.

Ich hatte ja, vielleicht rede ich mich ja noch gegenüber mir selbst, kann ich mich immer

sehr leicht rausreden, aber wenn ich es jetzt schon gesagt habe.

Ja, gib mal auf jeden Fall deine Bucketlist, dann erwähnen wir es mal öffentlich.

Ja, gut.

Das ist gut.

Ja, also interessant, dass man aus so einem Blogartikel

noch alles machen kann. Also wir hatten ja, glaube ich, ja vorher, bevor wir

einen Blog gefunden hatten, irgendwie, und dann war ja irgendwie

ergänzte Information. In demselben Blog habe ich

noch so ein paar andere Sachen entdeckt, die wir auch vorhaben,

sowas wie Datentypen sprechen und wie das implementiert

ist und wie halt das Python-Objekt-System

funktioniert oder die einzelnen Dinge oder

der C-Python-Compiler,

wie das überhaupt geht. Und da müssen wir auf jeden Fall

auch mal drüber sprechen. Aber schaut doch schon mal

in diesen Blog rein, 10.000 Meters Com, das fand ich wirklich

interessant. Ja, da waren einige gute Sachen dabei.

Ja, ziemlich.

Ja, ich habe mir auch dieses

C-Python-Internalist-Buch

besorgt.

Ja,

mal schauen.

Vielleicht kann man da auch noch ein bisschen was rausholen.

Ja, das werden wir auf jeden Fall, also vielleicht

verpusten wir jetzt tatsächlich so jeden dieser Blogposts.

Wir lesen die einfach vor.

Nein, das ist wirklich toll und ich glaube,

dass viel, was auch Hörer von uns gerne

interessiert und wissen wollen, was da irgendwie so passiert,

dass man so ein bisschen darüber redet, weil das machen wir ja.

So ein bisschen erklären, wie Python

als Sprache und so.

Ja, auch.

Ja, spannend.

Ja, super. Ich glaube, wir haben

über Impulse gar nicht mehr so viel zu sagen.

Ich habe gehört, Johannes hat sich extra einen Pick der Woche überlegt.

Ich habe mir tatsächlich einen Pick

und zwar GitHub Octo.

Das ist eine

Anwendung, die GitHub geschrieben hat,

mit der man Repositories

visualisieren kann.

Also die interne Struktur des Codes

in einem Repository.

so der Hintergrund ist

du kommst in ein neues Projekt rein

und da sind jetzt eine Million

Teilen Python-Code drin

und deine erste Aufgabe ist

mach mal hier eine Log-Ausgabe rein

es ist sehr schwer

sich da zurechtzufinden und es ist auch sehr schwer

Sachen zu finden in Projekten

wenn man sie nicht sehr genau

kennt und da ist eben GitHub

Octor, das macht hier so ein paar sehr schöne

Grafen, das zeigt quasi grafisch

und ich kann es jetzt mal ins Bild halten hier, zeigt quasi grafisch die Abhängigkeiten

zwischen den verschiedenen Dateien, wo die liegen und wer sich importiert und wie die

aufeinander aufbauen und dann kann man eben sehr schnell da so einen Überblick bekommen

darüber, was mit was interagiert und was wohin gehört.

Also schöne Kreisbeispiele hier zeigen.

Wundervoll, das sieht ja richtig kreativ aus.

Es sieht richtig schön aus.

Zum Ausdruck an die Wand hängen, also als Kunst jetzt.

Ja, zum einen das und zum anderen auch funktionale Kunst, wo man eben nachsehen kann, von wo nach wo man hin navigieren muss. Und auch interessant, weil es eben so auf eine gewisse Art und Weise die Architektur einer Software widerspiegelt, die ja sehr unterschiedlich sein kann. Also wenn man sich hier diese Screenshots anschaut, die sind ja zum Teil sehr unterschiedlich. Manche sind halt sehr flache Hierarchien.

Die Screenshots werden wir auch nehmen.

Sehr breit, selbstverständlich.

Und manche sind sehr gut aufgeteilt. Da sieht man vielleicht auch so ein bisschen den Style.

Genau, also es ist wirklich einfach

eine Einsicht, die man sonst nur sehr schwer

kriegen kann. Oder auch hier, also

hier gibt es eins,

wo man eben sieht, dass

jedes Paket quasi gleich ist und jedes Paket

hat auch so eine Testpunkt-Pi drin und das sind eben

halt diese grünen Punkte hier und man sieht, okay,

jedes Paket hat eins. Oder in einem anderen

Projekt sind die grünen Punkte halt alle in einem

großen Modul drin und

man sieht, okay, die sind nebendran, die sind offenbar nicht

integriert. Also es gibt einfach sehr

schnell einen Überblick über die Struktur

eines Projektes, was so an sich

nicht so einfach zu finden ist.

Das ist mein Pick

für diese Woche.

Ich würde picken Oh My Git.

Das ist ein Spiel,

wenn man Git lernen will.

Oh My Git?

Ich weiß gar nicht, was daraus geschrieben wurde.

Aber man kann es halt damit Git spielen

mit so Cards und lernt so ein bisschen über Git.

Natürlich auch so Beginner-Level und so, aber das ist halt

relativ spannend, wenn man so ein bisschen Advanced-Git

noch machen will. Also, wenn es nicht jetzt

Rebase Interactive und dann irgendwie gucken will,

dass man irgendwelche Commits stasht, dass man irgendwie

dann doch irgendwie die Message ändern und

was man da nicht so alles machen kann, so ein bisschen zu verstehen,

was das überhaupt ist. Cool, hört sich

aufspannend an. Sehr nice, ja, also

Gamification mit GIT

halt als kleines Spielchen ist schon irgendwie cool.

GITification. Ja, man sieht halt

auch immer ein bisschen visualisiert und man kann da so Sachen klicken

und das ist irgendwie ganz nett, also weil

ich meine, so Bratis oder so, jemand, der so ein bisschen programmiert

oder hat das ja irgendwann schon mal gesehen oder

viele Leute haben halt dann GIT nur zum

Push oder Pullen verwendet irgendwann.

Man kann echt tolle Sachen mitmachen.

Also spannende Sachen.

Deswegen ist es interessant, um so ein bisschen

Advanced dann auch zu machen.

Und geht ja auch in die gleiche Richtung. Ist ja spannend.

Ähnliche Picks haben die so.

Ja, hat auch was mit Git zu tun.

Lustigerweise.

Ja, auch bei dem

Backtail-Media-Pull-Request

ist mir das dann untergekommen,

weil

ich hatte halt gar nicht

gesehen, dass da irgendwelche

und normalerweise hat man immer so Linting-Steps oder so,

wo man jetzt irgendwie Software testet oder so.

Das war da jetzt gar nicht.

Da dachte ich mir, das ist schon mal ein bisschen komisch.

Und dann hat irgendwie bei GitHub,

hat dann irgendwie das Ding mich angemerkt,

hat so, dein Code ist ja irgendwie,

da sind ja die ganzen Linting-Geschichten nicht richtig

und da ist noch was falsch und es ist falsch.

Du warst schon überrascht, weil du hattest doch gemacht,

was da drin definiert ist.

Genau, und ich dachte schon so, ja gut, so mache ich das halt,

das ist doch normal und das ist doch okay.

Und dann dachte ich so, ja, wie passiert das eigentlich,

das GitHub das weiß, dass das nicht okay ist

und ja, dann wurde ich

auch darauf hingewiesen, so, ja

wir benutzen hier Precommit

benutzen das auch mal auch

und das ist auch ein ganz

das ist glaube ich auch noch ein Projekt von Anthony

Soti, ich weiß gar nicht, wie man den ausspricht

und

man definiert das quasi in so

einer Art Konfigurationsdatei

was man da gerne hätte

und dann sagt man Precommit

Install oder so und dann installiert

es alle Abhängigkeiten, die man braucht, um diese

Geschichten machen zu können lokal,

aber man muss diese Abhängigkeiten dann auch nicht mehr

im Projekt haben. Man hat ja normalerweise auch mal so eine ganze

Reihe von Dingen, ja, was weiß ich nicht,

Black, Flag8, dieses ganze

Zeugs, auch im gleichen Projekt

dann immer rumhängen und...

Das ist Death Dependencies quasi, Herr Sotz, oder?

Ne, ist nicht Death Dependencies.

Death Dependencies sind ja auch nochmal andere Sachen,

aber man hat halt diesen Kram dann da nicht

mehr drin, sondern das, ich weiß gar nicht,

dass ein eigenes Virtual

Environment installiert wird, ich weiß jetzt gar nicht genau,

wie es dann technisch funktioniert. Auf jeden Fall

ist es dann so, wenn man sagt, dann git commit oder so,

dann läuft das dann halt automatisch

durch und wenn

es nicht

richtig war, dann sagt es irgendwie, nee, kann ich

committen, weil da ist halt zum Beispiel irgendwie noch

ein, da ist ein

Plague 8 hat mir gesagt, da ist was faul oder

es sortiert hier halt einfach mal die Imports um mit

iSort oder es macht halt irgendwie

Man kann dann eigene Regeln anlegen, also jedes Mal muss man

über Droba was machen, ja okay. Genau.

Der Dockstring ist nicht lang genug.

Ja, also das

kannst du halt konfigurieren, wie du willst, aber

Es wird dann halt auch so mal

ein Comment gemacht.

Das ist natürlich auch ein bisschen hart.

Ja, klar.

Das ist ja schon mal super.

Das kann man ja relativ leicht hinfaken.

Ja, genau.

Aber das fällt ja schon mal auf, wenn er nicht da ist, zum Beispiel.

Ja, es ist natürlich relativ hart, aber es ist ja

eigentlich schon auch der richtige Zeitpunkt.

Du kannst nicht committen, ohne dass alles in Ordnung ist.

Genau, das heißt, es ist damit sichergestellt,

dass nicht irgendwelcher Quatsch da drin ist.

Wahrscheinlich kann man das dann auch irgendwie umgehen.

Ist das eine Library oder was?

oder ist das...

Ja, das ist ein Projekt, das ist auch ein Kommando-Zeilentool.

Man benutzt es als

Kommando-Zeilentool und man sagt im Grunde einmal

pre-commit install und dann guckt es halt in diese

Konfigurationsdateien, macht seine Magie

und danach sind diese Git-Hooks

gesetzt.

Das muss man quasi bei jedem Dev erstmal einmal installieren, damit das funktioniert.

Ja, okay.

Spannend.

Ja, fand ich auch gut.

Dann sind wir heute durch mit dem Thema

und vielen Dank, dass ihr uns wieder dazugehört habt.

Und egal wo ihr seid, morgens, mittags, abends, nachts

und bleibt uns gewogen, hört uns gerne

wieder, schaltet wieder rein und euch noch einen schönen

was auch immer Tag, Nacht,

bis demnächst.

Alles klar, bis demnächst.