Veröffentlicht am Schreib einen Kommentar

Unit Tests im Programmierkurs

testgetrieben-programmieren-lernen

Unit Tests im Programmierkurs – Test Driven Learning

“Hilfe – meine Lösung stimmt nicht mit der Beispiellösung überein!”
“Meine Lösung läuft zwar, aber ist sie auch korrekt?”

Programmieranfänger benötigen Aufgaben, viele Aufgaben. Und Beispiellösungen dazu. 

Doch ihre Unsicherheit bleibt: zu ein und derselben Aufgabe gibt es meistens mehrere korrekte Lösungen. Gehört die eigene Lösung dazu?

Unit Tests: das Zauberwort der Profis

Auch Profis kennen diese Herausforderung und zusätzlich wollen sie aus allen guten Möglichkeiten die beste wählen.

Anfängerinnen und Anfänger können noch gar nicht beurteilen, ob ihre Lösung überhaupt korrekt ist.

Software Engineers verlassen sich dazu gerne auf eine gute Testabdeckung ihres Codes. Sie sorgen also dafür, dass es genügend automatisierte Testfälle gibt, um sicherzustellen, dass auch nach einer Änderung die gesamte App korrekt läuft.
Code durch besseren Code ersetzen – das könnte ja eine solche Änderung sein.

Automatisierte Tests gehören zum modernen Software-Entwicklungszyklus. Und genau diese Philosophie dient auch den Anfängerinnen und Anfängern bei ihrer dringlichen Frage, ob ihre Lösung überhaupt korrekt ist:

Unit Tests: Sicherheit für Anfänger

Neben vielen Aufgaben und Beispiellösungen erhalten sie auch Testfälle, gegen die sie ihren Code testen.

Das folgende Bild zeigt ein Beispiel aus Sicht der Studierenden. Es ist eine sehr einfache Anfänger-Aufgabe in Python:

Training mit Testfällen
Beispiel einer einfachen testgetriebenen Python-Aufgabe für Anfänger mit Moodle 4 und Coderunner-Plugin.

Im Bereich oben steht die Aufgabenstellung und ein Beispiel eines möglichen Testfalls mit Input und erwartetem Ergebnis.

Die Lösung wird im Feld “Antwort” formuliert. Klickt man auf “Prüfen”, dann werden die automatisierten Tests ausgeführt. Der Code ist lauffähig und das Ergebnis steht unten im roten Bereich.

Offenbar sind in diesem Beipsile noch nicht alle Anforderungen aus der Aufgabenstellung erfüllt. Der Code wird korrigiert, bis das Ergebnis stimmt.

So erhalten die Studierenden die Sicherheit, dass sie auf dem richtigen Weg sind.

Unit Tests erstellen für Test Driven Learning

Die Art der Tests unterscheidet sich von den Testfällen bei produktiven Apps.

Es reicht meistens nicht, lediglich die Ausgabe zu testen – so wie im Beispiel oben.

Ein weiteres Beispiel:

Diese Aufgabenstellung gibt Code vor. Die for-Schleife soll als while-Schleife geschrieben werden. Eine wichtige Anfängerübung.

Beispiel Testfall
Typische Programmieraufgabe in einem Anfänger-Training. Diese Aufgabenstellung benötigt einen zielgerichteten Unit-Test.

Als Lösung wurde hier einfach der vorgegebene Code aus der Aufgabenstellung einkopiert.

Wenn die Testfälle jetzt nur den Output prüfen, dann wäre diese Lösung korrekt.

Doch die Aufgabe wurde gar nicht gelöst – die for-Schleife wurde nicht in eine while-Schleife umformuliert.

Verbesserter Test Case

Als Testfall könnten wir jetzt den Text im Antwortfeld nehmen und nach dem String ‘while’ suchen.

Kommt ‘while’ vor und stimmt der Output mit der Erwartung überein, dann ist die Aufgabe korrekt.

Aber: Die Lösung im Screenshot enthält den String ‘while’ jedoch steht er im Kommentar und nicht wie gefordert im Code selbst.
Die Test-Methode findet den String ‘while’, die Aufgabe wurde dennoch nicht gelöst.

Finalisierter Unit Test

In Python können wir mit ast-Modul den Code parsen. ast steht für Abstract Syntax Tree. Der Screenshot zeigt die Idee:

Der String, der die Lösung enthält, wird also geparst und anhand des Syntax-Trees können wir entscheiden, ob tatsächlich eine for-Schleife verwendet wurde.

Im Beispiel oben wird der Lösungsstring in Zeilen 5-8 aufbereitet.

Der Syntax-Tree wird lediglich mit pprint ausgegeben. Um robuste Test-Fälle zu schreiben, werden wir den Syntax-Tree mit ast.NodeVisitor untersuchen.

Schon bei der Ausgabe mit pprint sehen wir, dass der Kommentar im Syntax-Tree nicht auftaucht.

Wir suchen im Syntax-Tree nach einem Knoten für ‘while’ und finden diesen nicht. Demnach können wir zweifelsfrei feststellen, dass die Aufgabe nicht im Sinne der Aufgabenstellung gelöst wurde.

Fazit

Aufgabenstellungen für Test Driven Learning sind mit besonderer Sorgfalt zu entwickeln. Immerhin müssen wir dazu die passenden Testfälle schreiben und das ist ziemlich aufwändig.

Allerdings lohnt sich der Aufwand – denn der Anfänger erhält ein Instrument an die Hand, das diese dringende Frage beantwortet: “Stimmt meine Lösung”.

Spiel mit Python 1 ist nicht einfach noch ein Python Training. Vielmehr ist es eines der wenigen Python Trainings mit Testfällen und erst noch in deutscher Sprache.

  • Python ist eine vielseitige Programmiersprache. Sie wird gerne genutzt, für Datenanalysen, Data Science und neu auch, um KI-gestützte, intelligente Apps zu entwickeln.

  • LLM-Tipps & Fachglossar

    Abonniere meinen Newsletter, erhalte regelmäßig Tipps und Tricks über den produktiven Einsatz von LLMs und ich schenke dir mein umfangreiches Fachglossar Von AI-Engineering bis Zero-Shot

  • Sentence Embeddings für Vektordatenbanken
  • LLMs in Enterprise Search
  • Prompt Engineering Personas und Wiederholungen
  • Chatbot als Lernassistent
  • AI-Engineering-Fachglossar
Veröffentlicht am Schreib einen Kommentar

Ist mein Code korrekt?

Online Programmieren Lernen Qualität

Ist mein Code korrekt?

Das ist die Frage der Fragen – nicht nur für Anfänger in der Programmierung. Immerhin gibt es zu einer Aufgabenstellung meistens mehr als eine korrekte Lösung. Die Musterlösung ist lediglich ein Beispiel einer möglichen Lösung. Wie also können wir wissen, ob unser Code korrekt ist?

Die Fragestellung ist alt – die Antwort (vielleicht) überraschend:

es gibt keine Möglichkeit, die Korrektheit von Code eindeutig sicherzustellen. Die Theoretiker haben sich intensiv damit befasst.

Und doch verlassen wir uns mit der Digitalisierung nahezu blind darauf, dass Code richtig funktioniert.

Welch riesige Verantwortung für die Programmierer!

Was bedeutet schon ‘richtig funktionieren’? Und wer sagt, ob das Programm ‘richtig funktioniert’?

Gehen wir zunächst dieser Frage nach.

Diffuse Anforderungen erheben – Requirements Engineering

Wissen die Endanwender unserer Programme überhaupt, was sie wollen?

Diese Antwort ist einfach: nein, meistens nicht.

Jedenfalls nicht so genau oder nicht genau genug, um daraus eine eindeutige Anforderung an ein Programm zu formulieren und zwar so präzise, dass die Programmierer in jedem Fall eindeutig wissen, was zu tun ist.

Die Erhebung dieser Anforderungen ist ein langer Prozess mit einem Moving Target.

Und doch gibt es so viele gut funktionierende Programme, dass wir uns im Rahmen der Digitalisierung immer abhängiger davon machen.

Requirements Engineering ist ein Beruf geworden. Wer diesen ausübt, erhebt die Anforderungen der Auftraggeber und Endnutzer, schreibt sie auf, und formalisiert sie so, dass daraus relativ eindeutige Arbeitsaufträge abgeleitet werden können.

Sobald die Endanwender das fertige Programm sehen, werden sie viel besser sagen können, was sie eigentlich meinten und ihre Anforderungen präziser ausdrücken können.

Aus dieser Erkenntnis hat sich das agile Vorgehen herauskristallisiert: ein Team entwickelt in kurzen Zyklen kleine Teile der Funktionalität der App, so dass die Enduser anhand des fertigen Programms ihre Anforderungen präzisieren können. So wächst das Programm nach und nach.

Die Requirements Engineers sind an vorderster Front tätig und sie können’s gut mit Menschen.

Software Engineering

Software Engineers zerlegen die Requirements, also die Anforderungen,  in kleine Stücke und diese wiederum in kleinere Stücke, bis ganz einfach formulierbare Einheiten (Units) daraus entstehen.

So einfach, dass sie  jede Einheit gut beschreiben und auch gut testen können.

Dann programmieren sie Einheit um Einheit, testen sie, und setzen sie zusammen zu einem Großen und Ganzen, testen auch dieses und überlassen diese App den Auftraggebern.

Diese begutachten die App und stellen neue Anforderungen.

Software wird heutzutage in solchen kurzen Zyklen nach und nach entwickelt.

Das Dilemma der Anfänger

Wer Programmieren lernt, fängt an mit kleinen Aufgaben – etwa so groß wie diese Einheiten (oder Units), in die produktive Programme zerlegt werden.

Wer lernen und üben will, benötigt also viele solcher Aufgaben.

Erschwerend kommt hinzu, dass es zu einer einzelnen Aufgabe in der Regel viele mögliche und korrekte Lösungen gibt. Nicht nur die Beispiellösung, die wir vielleicht auch erhalten.

Und da entsteht die große Unsicherheit: Wie weiß ich als Anfänger, ob mein Code richtig funktioniert?

Die Antwort auf die Frage holen wir uns in der Praxis: Wie weiß ich als Profi, ob mein Code richtig funktioniert?

Im Rahmen der Entwicklungszyklen sind oft kleinste Änderungen am Code notwendig. Wie kann ich sicher sein, dass das Große Ganze  noch korrekt funktioniert?

Diese Frage ist bei der Programmierung so zentral, dass ein weiteres Berufsfeld entstanden ist: Das Test Engineering.

Test Engineering

Ein Test Engineer nimmt die Vorgaben des Requirements Engineers und die Aufteilung der Aufgaben in Units der Software Engineers und schreibt daraus Testfälle – so genannte Unit-Tests.

Das sind eigenständige Programme, die den Code der Programmierer automatisch testen.

Ändere ich als Programmiererin oder Programmieren meinen Code an einer Stelle leicht ab, dann lasse ich die ganze Test-Suite laufen.

Ist sie erfolgreich, dann kann ich (ziemlich) sicher sein, dass das Gesamtprogramm weiterhin korrekt läuft.

Jedenfalls gleich korrekt wie zuvor – denn auch Test Engineers sind nicht unfehlbar.

Testfälle entwickeln ist einerseits aufwändig und andererseits ein zentraler Erfolgsfaktor bei der Software-Entwicklung.

Gerade weil die Programme zuerst in Zyklen entwickelt werden und später ständig gepflegt werden. Testfälle sichern die Qualität.

Die Berufsbilder werden nicht überall  scharf getrennt und eine Person kann alle Aufgaben wahrnehmen.

TDD beim Programmieren lernen

Schreiben wir zuerst die Testfälle und erst dann den Code dazu, dann werden die Testfälle zur Spezifikation für die Programmierer.

Man spricht von Test Driven Development (TDD).

TDD ist dann auch die Antwort auf die eingangs gestellte Frage:

Wenn wir jetzt Programmieren lernen, dann können wir sicher sein, dass unser Code richtig läuft, wenn wir nicht nur viele Übungsaufgaben erhalten, und mögliche Beispiellösungen dazu, sondern auch Test-Suiten- die uns helfen sicher zu sein, dass die selbst erdachte Lösung korrekt funktioniert.

Erfahrene Coaches schenken den Unit Tests in einem Programmierkurs spezielle Aufmerksamkeit und entwickeln sie mit Sorgfalt im Hinblick auf die Aufgabenstellung.

Lernen mit Unit Tests

Das Video zeigt ein sehr einfaches Beispiel, wie Lernaufgaben in Python mit Hilfe von Unit Tests formuliert und ausgeführt werden.

Fazit:

Die Unsicherheit, ob der Code korrekt funktioniert, begleitet Programmierer durchs Berufsleben.

Funktionierende Software wird in kurzen Zyklen gemeinsam mit den Endusern und Auftraggebern entwickelt.

Gut entworfene und gepflegte Testfälle verringern die Unsicherheit, erhöhen die Code-Qualität und sind ein unverzichtbares Element bei der langfristigen Pflege von Code.

Auch Anfänger profitieren von Testfällen für ihre Trainingsaufgaben.

  • Python ist eine vielseitige Programmiersprache. Sie wird gerne genutzt, für Datenanalysen, Data Science und neu auch, um KI-gestützte, intelligente Apps zu entwickeln.

  • LLM-Tipps & Fachglossar

    Abonniere meinen Newsletter, erhalte regelmäßig Tipps und Tricks über den produktiven Einsatz von LLMs und ich schenke dir mein umfangreiches Fachglossar Von AI-Engineering bis Zero-Shot

  • Sentence Embeddings für Vektordatenbanken
  • LLMs in Enterprise Search
  • Prompt Engineering Personas und Wiederholungen
  • Chatbot als Lernassistent
  • AI-Engineering-Fachglossar
Veröffentlicht am Schreib einen Kommentar

Zeit sparen beim Dokumentieren: einfacher Trick

Zeit sparen bei Dokumentieren

Zeit sparen beim Dokumentieren: einfacher Trick

Nur dokumentierter Code ist guter Code. Das hören wir immer wieder und wissen es aus Erfahrung.

Doch endlich läuft der Code und wir haben noch sooo viel zu tun – also nehmen wir uns ganz fest vor: morgen wird dokumentiert. 

Mit einem einfachen Trick dokumentiert der Code sich selbst.

Sprechende Bezeichner!

Genau: “Bezeichner” und nicht “Bezeichnung”.

Bezeichner sind die Namen für Variablen, für Funktionen, Methoden, Klassen, Objekte, etc.

Ein kurzer Test:

Welcher (Python) Code ist besser verständlich

x = 1

oder 

anzahl_autos = 1

Autorin: Ursula Deriu

Bezeichner für den Computer

Für den Computer ist es einerlei: sowohl x als auch anzahl_autos, beides sind Bezeichner (englisch: identifier).

Der jeweilige Compiler – oder im Fall von Python der Python-Interpreter – löst den Bezeichner auf in eine interne Adresse und sorgt dafür, dass jedes Vorkommen des Bezeichners jeweils mit derselben internen Adresse aufgelöst wird.

Diese interne Adresse verweist auf eine Stelle im Memory – genauer im RAM (Random Access Memory) und an dieser Stelle wird das Programm den aktuellen Wert finden, mit dem es rechnen soll.

In diesem Beispiel bezeichnen x und anzahl_autos zwei Variablen. Der Grund ist ein einfacher, der Wert, der Variable kann ändern. In unserem Beispiel oben, ist er jeweils 1 also ein konstanter Wert.

Mit dem Wert der Variablen können wir rechnen – Beispiel:

x = x * 2

anzahl_autos = anzahl_autos * 2

Für den Computer bedeuten die beiden Codezeilen das Gleiche:

Der aktuelle Wert der Variablen wird mit Hilfe der internen Adresse aus dem RAM geholt und in eines der Register in der CPU geschrieben. Danach wird der Wert mit 2 multipliziert und das Ergebnis wird aus dem Register wieder an die mit der internen Adresse bezeichneten Stelle im RAM geschrieben.

Sprechende Bezeichner

Für den Menschen ist der Unterschied jedoch erheblich:

anzahl_autos = anzahlAutos * 2;

anzahl_kalorien = anzahl_kalorien * 2

gehalt = gehalt * 2

Blitzschnell leuchtet in unserem Gehirn jeweils ein völlig anderes Bild auf. Der nackte Code erhält Kontext und das Programm wird besser verständlich.

Es lohnt sich, beim Programmieren die Bezeichner mit Bedacht zu wählen. Das Programm und dessen Absicht werden gleich viel besser verständlich.

Sprechende Bezeichner dokumentieren Funktionen und Methoden

Dasselbe gilt für die Bezeichner von Funktionen und Methoden.

def y(x):
    return (x * 2)

def verdopple_das_verkehrsaufkommen(anzahl_autos):
    return(anzahl_autos * 2)

Die Funktion y und die Funktion verdopple_das_verkehrsaufkommen sind für den Computer absolut identisch.

Nicht jedoch für den menschlichen Leser.
y als Bezeichner für die Funktion gibt uns keinen Kontext. Um sie zu verstehen, müssen wir den Code genau lesen. Zugegeben: in diesem Beispiel ist das trivial.
Doch das ist die Ausnahme – Funktionen können weitere Funktionen aufrufen, sogar sich selbst. Funktionen können beliebig komplex sein.

Wir könnten bei der Funktion y einen Kommentar einfügen, um die Absicht der Funktion zu erklären – das ist sowieso eine gute Idee, bedeutet aber, dass wir neben dem Programmcode immer auch die Kommentare pflegen müssen.

Und wir müssen uns bei der Analyse des Codes genau erinnern, was y und was x bedeutet.

Es geht auch einfacher: Wir wählen sprechende Bezeichner – so wie bei der Funktion verdopple_das_verkehrsaufkommen und das Programm dokumentiert sich selbst.

Deprecated Code oder: Bezeichner pflegen

Die Medaille hat auch eine Kehrseite: Sprechende Bezeichner erzeugen beim menschlichen Leser einen Kontext und sie können damit in die Irre führen.

def verdopple_das_verkehrsaufkommen(anzahl_autos):
    return(anzahl_autos * 3)

Hier verspricht die Bezeichnung ein Verdoppeln – der Code jedoch verdreifacht den Wert der übergebenen Variablen.

Das bedeutet also, dass wir entweder den Bezeichner der Funktion überall anpassen oder aber, eine neue Funktion schreiben.

Bezeichner anpassen

Anpassen der Bezeichnung ist wiederum ein zweischneidiges Schwert – ist das Programm nicht brandneu, dann wissen wir nicht, ob die Funktion nicht schon von weiteren Programmen verwendet wurde.

Wir müssen also vorsichtig sein, uns schreiben besser eine neue Funktion mit einer neuen sprechenden Bezeichnung.

Deprecated

Die alte Funktion können wir als deprecated bezeichnen, und so den Programmierern, die sie vielleicht schon verwendet haben, anzeigen, dass wir sie in Zukunft löschen werden.

Der Computer hält uns nicht davon ab, beliebigen Unsinn zu treiben. Folgendes ist formal gültiger Code:

anzahl_kalorien = 95
kalorien_die_du_essen_darfst = verdopple_das_verkehrsaufkommen(anzahl_kalorien)

Der Computer wird die Berechnung emotionslos ausführen und an der Speicherstelle kalorien_die_du_essen_darfst die Zahl 190 speichern und damit weiterrechnen.

Ob wir als Programmierer den Code noch verstehen, ist jedoch sehr zu bezweifeln. Es lohnt sich, eine neue Funktion mit passendem Bezeichner zu schreiben und so den inhaltlichen Kontext “Verkehrsaufkommen” vom Kontext “Kalorienbedarf” zu trennen.

[/vc_row_inner]

Fazit:

  • Sprechende Bezeichner schaffen Kontext für den Menschen. Der Code dokumentiert sich selbst.
  • Sie ergänzen die Kommentare und kürzen die Kommentare ab.
  • Die Bezeichner sind mit Bedacht zu wählen und müssen der Funktionalität entsprechen.
  • Deprecated sagt aus, dass eine Funktion in Zukunft nicht mehr verfügbar sein wird.
  • Sentence Embeddings für Vektordatenbanken
  • LLMs in Enterprise Search
  • Prompt Engineering Personas und Wiederholungen
  • Chatbot als Lernassistent
  • AI-Engineering-Fachglossar
  • Python ist eine vielseitige Programmiersprache. Sie wird gerne genutzt, für Datenanalysen, Data Science und neu auch, um KI-gestützte, intelligente Apps zu entwickeln.

  • LLM-Tipps & Fachglossar

    Abonniere meinen Newsletter, erhalte regelmäßig Tipps und Tricks über den produktiven Einsatz von LLMs und ich schenke dir mein umfangreiches Fachglossar Von AI-Engineering bis Zero-Shot

Veröffentlicht am Schreib einen Kommentar

Die Zuweisung (assignment operator)

Zuweisungsoperator

Die Zuweisung (assignment operator)

Was bedeutet die folgende Zeile:

x = 1

Die Antwort auf die Frage ist gar nicht so einfach: es fehlt der Kontext. In diesem Artikel gehen wir der Bedeutung des Gleichheitszeichens nach. 

Gleichheit in der Mathematik

Eine Erinnerung an den Mathematikunterricht wird wach:

x ist eine Variable und 1 ist der Wert der Variable. Damit können wir Gleichungssysteme lösen, wie zum Beispiel dieses:

x = 1
y = 2
z = x + y

Für den Mathematiker bedeutet x = 1 also

Der Ausdruck rechts vom =-Zeichen gleichwertig ist mit dem Ausdruck links vom =-Zeichen.

1 = x enthält dieselbe Aussage.

Zuweisungsoperator in der Informatik

x = 1

Diese Zeile bedeutet in den meisten Programmiersprachen eine Zuweisung. Die Langform wäre:

Der Variablen mit der Bezeichnung x weisen wir den konstanten Wert 1 zu. Im weiteren Verlauf des Programms wird die Variable mit der Bezeichnung x den konstanten Wert 1 haben, und zwar solange bis der Variablen mit Bezeichnung x einen neuer Wert zugewiesen wird.

Nicht alle Programmiersprachen verwenden dazu das = Zeichen

Cobol verlangt: 

move 1 to x.

In Pascal ist es:

 x := 1;

Bleiben wir beim = Zeichen für den Zuweisungsoperator.

Gleich ist nicht gleich Gleich

Beispiel: Gleichheit vs. Zuweisung

x = 1
x = 2

Diese zwei Zeilen bereiten dem Mathematiker Kopfzerbrechen. Als Gleichungssystem aufgefasst bedeuten die beiden Zeilen: 1 = 2 – was ja nicht möglich ist.

Dieselben zwei Zeilen sind Alltag für den Informatiker: Zuerst nimmt x den Wert 1 an. Und danach nimmt x den Wert 2 an. Das ist alles.

 

Noch ein Beispiel: Gleichheit vs. Zuweisung und die Reihenfolge

1 = x

Für den Mathematiker bedeutet 1 = x dasselbe wie x = 1

1 = x bietet dem Informatiker Kopfzerbrechen, weil die Zuweisung immer den Wert rechts vom Zuweisungsoperator in die Variable links vom Zuweisungsoperator schiebt. Und bei 1 = x steht links vom Zuweisungsoperator nicht eine Variable, sondern der konstante ganzzahlige Wert 1. Untersuchen wir das genauer:

Speicherplatz im Memory (RAM)

Aus Sicht des Computers bedeutet x noch etwas anderes: x belegt Speicherplatz im Memory (RAM = Random Access Memory).

Wie viel Speicherplatz belegt wird, hängt ganz vom Datentyp von x ab. In unserem ‘Programm’ haben wir keine Aussage darüber gemacht.

Python und Memory

Handelt es sich um ein Python Programm, dann wird der Python (genauer der Python-Interpreter) dem Kontext entnehmen, dass x eine ganze Zahl sein muss und entsprechend viel Platz im Memory dafür reservieren.

Java und Memory

Handelt es sich um ein Java-Programm, dann müssen wir als Programmierer Java (genauer dem Java-Compiler) mitteilen, von welchem Datentyp x sein soll.

Mit

int x = 1;

teilen wir Java mit, dass die Variable mit der Bezeichnung x den Datentyp int haben soll und zu Beginn den Wert 1 annehmen soll. Im weiteren Verlauf des Programms brauchen wir den Datentyp von x nicht mehr zu definieren. Also

int x = 1;
x= 2;

Ist gültiger Java Code.

int bedeutet für den Java-Compiler, dass 32 Bit Platz im Memory zur Verfügung gestellt werden. Ein Bit ist ja diejenige Einheit, die den Wert 0 oder 1 annehmen kann.

8 aufeinanderfolgende Bit werden als Byte bezeichnet. Und ein Byte ist die kleinste, adressierbare Einheit in einem Computer. Adressierung ist notwendig, um im Memory den Wert von x sehr schnell zu finden.

32 Bit sind also 4 Byte

Mit dem Befehl int x = 1 weisen wir in Java also den Compiler an, im Memory nach 4 aufeinanderfolgenden Byte zu suchen, die noch frei sind und diese für den Wert der Variablen mit Bezeichnung x zu reservieren.

Diese 4 Byte werden für die Dauer des Programms den Wert von x in binärer Form enthalten. Der Wert von x kann sich ständig ändern, je nachdem, was der Programmcode verlangt.

Wir können also schreiben:

int x = 4
x = 2 * x

Damit passiert folgendes:

  1. Es werden 4 Byte Platz reserviert für x und mit dem Wert 4 belegt.
  2. In der nächsten Zeile wird zuerst der Ausdruck rechts vom Zuweisungsoperator ausgewertet: Der Wert von x wird genommen (also 4) und mal 2 gerechnet (also 8)
  3. Jetzt erfolgt die Zuweisung: Das Ergebnis (also 8) wird in die 4 Byte, die für x reserviert sind, geschrieben und damit geht der frühere Wert (also 4) vergessen.

Die Umwandlung zwischen den für uns gewohnten Dezimalzahlen in die Binären Zahlen mit 0 und 1 überlassen wir getrost dem Computer.

Die Wahl des Datentyps

Als Java Programmierer wählen wir den Datentyp sorgfältig. Zu jeder Zeit müssen genügend Bit und Byte vorhanden sein, um alle möglichen Werte für die Variable darzustellen.

Mit long x = 1 weisen wir Java an, 64 bit für x zu reservieren – also 8 Byte.

In Python ist das Leben als Programmierer einfacher. Der Python-Interpreter teilt die Datentypen zu und geht dabei sehr großzügig um mit den Bytes im Memory.

Das ist ein wichtiges Kriterium bei der Wahl der Programmiersprache:

Bei einer typsicheren Sprache wie Java, C,  C#  können wir als Programmierer den Speicherbedarf gut steuern und optimieren.
Bei einer nicht-typsicheren Sprache, wie Python, ist das nicht der Fall – dafür codieren wir schneller.

Platz gegen Zeit – ein häufiger Trade Off in der Informatik.

Fazit:

Das = Zeichen wird in der Informatik als Zuweisungsoperator verwendet und hat damit eine grundsätzlich andere Bedeutung als das Gleichheitszeichen in der Mathematik.

In der Informatik steht links vom Zuweisungsoperator immer die Bezeichnung einer Variablen.
Rechts vom Zuweisungsoperator steht ein beliebiger Ausdruck.
Wird die Zuweisung ausgeführt, dann wird der Ausdruck rechts vom Zuweisungsoperator ausgewertet und in den Speicherplatz geschrieben, der für die Variable links vom Zuweisungsoperator im RAM reserviert wird.
Jede Variable hat einen Datentyp, dieser gibt an, wie viel Speicherplatz belegt wird.
Nur in typ-sicheren Sprachen kümmert sich der Programmierer um die Datentypen und optimiert den Memory-Bedarf des Programms.

  • Sentence Embeddings für Vektordatenbanken
  • LLMs in Enterprise Search
  • Prompt Engineering Personas und Wiederholungen
  • Chatbot als Lernassistent
  • AI-Engineering-Fachglossar
  • Python ist eine vielseitige Programmiersprache. Sie wird gerne genutzt, für Datenanalysen, Data Science und neu auch, um KI-gestützte, intelligente Apps zu entwickeln.

  • LLM-Tipps & Fachglossar

    Abonniere meinen Newsletter, erhalte regelmäßig Tipps und Tricks über den produktiven Einsatz von LLMs und ich schenke dir mein umfangreiches Fachglossar Von AI-Engineering bis Zero-Shot

Veröffentlicht am Schreib einen Kommentar

Strings formatieren in Python

Strings formatieren Python

Strings formatieren in Python

Leserliche Texte sind die Schnittstelle zwischen Menschen und Computer. Strings formatieren geht mit Python besonders einfach.

In diesem Blog-Post erfährst du folgendes:

  • Wie du Zeichenketten mit Python formatierst.
  • Wie du mit dem Datentyp datetime arbeitest.
  • Einfache Beispiele, wie du Konstanten und Funktionen aus Programmbibliotheken importierst.

Der Blog-Post ist Teil von Spiel mit Python – ein Online Programmiertraining für absolute Anfänger.

Strings formatieren mit Python – ein einfaches Beispiel

import datetime
jetzt = datetime.datetime.now()
temperatur = 31.57
print (f'Heute ist der {jetzt:%d.%m.%Y} und es sind {temperatur:.1f} °C')

Probiere gleich aus: Öffne den Playground und kopiere den Code in das Eingabefeld, das du dort oben links findest.

Lies hier weiter, um zu verstehen, was da passiert.

f-Strings mit Python

Das ist ein Beispiel dafür, wie mit Python die Ausgabe des Programms schön gestaltet werden kann. Im Code Snippet verwenden wir zwei Variablen

  • jetzt
  • temperatur

Die Ausgabe wird anders aussehen, je nachdem, welche Werte die beiden Variablen haben. Am besten probierst du das gleich aus.

Doch bauen wir dein Wissen über String-Formatierung der Reihe nach auf.

Der “+” Operator zur String-Konkatenierung

Das einfachste Beispiel:

print('Hello World')

Ausgabe: Hello World

Dabei ist ‘Hello World’ eine konstante Zeichenkette.

Wir könnten auch eine Variable einführen:

zeichen = 'Hello World'
print(zeichen)

Ausgabe: Hello World

 

Oftmals kommen wir in die Lage, zwei Zeichenketten für eine Ausgabe zu kombinieren:

print(zeichen + zeichen)

Ausgabe: Hello WorldHello

 

Die Ausgabe ist nicht gut lesbar und wir fügen ein Leerzeichen ein:

print (zeichen + '  '+ zeichen)

Ausgabe: Hello World Hello World

Doch das Aufbereiten von Zeichenketten mit dem “+” Operator ist unnötig aufwändig. Es gibt in Python3 eine sehr viel einfachere Möglichkeit:

f-Strings in Python – schnell und einfach schöne Strings erstellen

print (f'{zeichen})
print(f'{zeichen} {zeichen}')

Ausgabe: Hello World Hello World

So einfach ist das: mit f” wird die zu formatierende Zeichenkette gekennzeichnet.

Mit geschweiften Klammern umgeben wir die Variablen, die Python in der Zeichenkette einsetzen soll.

Und so können wir weitere Zeichen in den Ausgabestring hinzufügen:

print(f'{zeichen} und nocheinmal {zeichen}')

Ausgabe: Hello World und nocheinmal Hello World

f-Strings mit numerischen Werten

Oftmals wollen wir Zahlen für die Ausgabe formatieren. Auch dabei unterstützen uns die f-Strings.

Probiere gleich aus und verändere auch den Wert der Variablen Zahl:

zahl = 42
print (f'{zahl:<4}' )

Die Zahl wird linksbündig dargestellt – im Browser hat das keinen Effekt.

print (f'{zahl:_<4}')

Derselbe Effekt wie oben, aber die Zahl wird Links mit _ aufgefüllt bis sie insgesamt die Länge 4 erreicht. Man spricht von Padding.

print (f'{zahl:0>4}')

Derselbe Effekt wie oben, aber mit Nullen aufgefüllt.

print (f'{zahl:04d}')

Nochmals derselbe Effekt: Die Zahl wird vierstellig dargestellt und links mit Nullen aufgefüllt

Es brauchen nicht 4 Stellen zu sein, du kannst auch andere Werte einsetzen. Auch mit dem Padding-Zeichen kannst du spielen und es verändern.

 

Und jetzt kombinieren wir:

print (f'Die Zahl hat den Wert {zahl:0>4}')

Ausgabe: Die Zahl hat den Wert 0042

Aufpassen mit dem < und dem > Zeichen. Probiere gleich aus.

 

Interessant ist auch diese Möglichkeit:

print(f'{zahl=:0>4}')

Ausgabe: zahl=0042

 

Auch die Nachkommastellen können wir beeinflussen:

grösse=1.827
print(f'{grösse:.5f}')

Ausgabe: 1.82700

Nach dem Komma werden rechts Nullen aufgefüllt um die gewünschte Anzahl Zeichen zu erreichen, ein anderes Zeichen wäre nicht sinnvoll.

Und es wird sogar korrekt gerundet:

print(f'{grösse:.2f}')

Ausgabe: 1.83

 

Ausgehend von grösse=1.827.

Und wir können die Darstellung vor und nach dem Komma beeinflussen.

print (f'{grösse:0>12.5f}')

Ausgabe: 000001.82700

Also 12 Stellen insgesamt, davon 5 nach dem Komma und links mit Nullen gepaddet.

Auch die Tausender-Trennung ist möglich:

x = 1000000
print(f'{x:,}')

Ausgabe: 1,000,000

Als Trennzeichen sind allerdings nur die folgenden möglich: , und _

 

Datumsformatierung

Wir müssen oft mit Datums- und Zeitvariablen arbeiten und diese darstellen. Wir können unser Laptop nach dem aktuellen Datum und der aktuellen Zeit fragen:

 

import datetime
jetzt= datetime.datetime.now()
print(jetzt)

Die Ausgabe ist bei mir gerade: 2022-08-22 16:29:30.850000

Wir importieren die Library (Programmbibliothek) datetime.

Wir holen das aktuelle Datum und die aktuelle Zeit ab und versorgen diesen Wert in der Variablen mit der Bezeichnung jetzt und geben diese aus. Die Ausgabe erfolgt nicht im bei uns gebräuchlichen Format. Mit den f-Strings können wir datetime-Werte einfach formatieren:

print(f'Heute ist der {jetzt:%d.%m.%Y}')

Die Ausgabe ist bei mir jetzt gerade: Heute ist der 22.08.2022

Und damit haben wir alle Elemente vorgestellt, um das Code-Snippet zu verstehen und nachzubauen.

  • Sentence Embeddings für Vektordatenbanken
  • LLMs in Enterprise Search
  • Prompt Engineering Personas und Wiederholungen
  • Chatbot als Lernassistent
  • AI-Engineering-Fachglossar

Python Listen – einfache Übungen

Wende die Theorie praktisch an und vertiefe dein Verständnis. Entwickle die Lösungen der Challenges im Playground.

Challenge

Hole in der Programmbibliothek math die Variable pi ab. Das geht so:

from math import pi
print (pi)

Erzeuge die folgende Ausgabe:

pi=3.142
Pi=003.142
Ein Kreis habe den Radius 2.5.
Berechne die Fläche des Kreises und zwar so, dass das Programm auch für andere Radien funktioniert.
Erzeuge die folgende Ausgabe:
Ein Kreis mit Radius 2.5 hat die Fläche 19.6

Challenge

Erstelle mit einem Programm diese Tabelle

Radius=0 Umfang=000.000 Fläche=000.000
Radius=1 Umfang=006.283 Fläche=003.142
Radius=2 Umfang=012.566 Fläche=012.566
Radius=3 Umfang=018.850 Fläche=028.274
Radius=4 Umfang=025.133 Fläche=050.265
Radius=5 Umfang=031.416 Fläche=078.540
Radius=6 Umfang=037.699 Fläche=113.097
Radius=7 Umfang=043.982 Fläche=153.938
Radius=8 Umfang=050.265 Fläche=201.062
Radius=9 Umfang=056.549 Fläche=254.469
  • Python ist eine vielseitige Programmiersprache. Sie wird gerne genutzt, für Datenanalysen, Data Science und neu auch, um KI-gestützte, intelligente Apps zu entwickeln.

  • LLM-Tipps & Fachglossar

    Abonniere meinen Newsletter, erhalte regelmäßig Tipps und Tricks über den produktiven Einsatz von LLMs und ich schenke dir mein umfangreiches Fachglossar Von AI-Engineering bis Zero-Shot