diff options
Diffstat (limited to 'de-de')
-rw-r--r-- | de-de/asciidoc-de.html.markdown | 6 | ||||
-rw-r--r-- | de-de/bash-de.html.markdown | 4 | ||||
-rw-r--r-- | de-de/bc.html.markdown | 102 | ||||
-rw-r--r-- | de-de/c++-de.html.markdown | 1158 | ||||
-rw-r--r-- | de-de/c-de.html.markdown | 869 | ||||
-rw-r--r-- | de-de/css-de.html.markdown | 6 | ||||
-rw-r--r-- | de-de/d-de.html.markdown | 64 | ||||
-rw-r--r-- | de-de/dhall-de.html.markdown | 380 | ||||
-rw-r--r-- | de-de/git-de.html.markdown | 2 | ||||
-rw-r--r-- | de-de/html-de.html.markdown | 16 | ||||
-rw-r--r-- | de-de/java-de.html.markdown | 2 | ||||
-rw-r--r-- | de-de/javascript-de.html.markdown | 4 | ||||
-rw-r--r-- | de-de/latex-de.html.markdown | 8 | ||||
-rw-r--r-- | de-de/make-de.html.markdown | 43 | ||||
-rw-r--r-- | de-de/markdown-de.html.markdown | 2 | ||||
-rw-r--r-- | de-de/nix-de.html.markdown | 22 | ||||
-rw-r--r-- | de-de/python-de.html.markdown | 306 | ||||
-rw-r--r-- | de-de/python3-de.html.markdown | 655 | ||||
-rw-r--r-- | de-de/pythonlegacy-de.html.markdown | 766 | ||||
-rw-r--r-- | de-de/yaml-de.html.markdown | 4 |
20 files changed, 3600 insertions, 819 deletions
diff --git a/de-de/asciidoc-de.html.markdown b/de-de/asciidoc-de.html.markdown index 24100e0b..e3f64a00 100644 --- a/de-de/asciidoc-de.html.markdown +++ b/de-de/asciidoc-de.html.markdown @@ -88,7 +88,7 @@ Abteilungstitel Listen -Um eine Aufzählung zu erstellen verwendest du Sternchen. +Um eine Aufzählung zu erstellen, verwendest du Sternchen. ``` * foo @@ -96,7 +96,7 @@ Um eine Aufzählung zu erstellen verwendest du Sternchen. * baz ``` -Um eine nummerierte Liste zu erstellen verwendest du Punkte. +Um eine nummerierte Liste zu erstellen, verwendest du Punkte. ``` . item 1 @@ -104,7 +104,7 @@ Um eine nummerierte Liste zu erstellen verwendest du Punkte. . item 3 ``` -Um Listen zu verschachteln musst du zusätzliche Sternchen beziehungsweise Punkte hinzufügen. Dies ist bis zu fünf Mal möglich. +Um Listen zu verschachteln, musst du zusätzliche Sternchen beziehungsweise Punkte hinzufügen. Dies ist bis zu fünf Mal möglich. ``` * foo 1 diff --git a/de-de/bash-de.html.markdown b/de-de/bash-de.html.markdown index 7a0db157..3a76708a 100644 --- a/de-de/bash-de.html.markdown +++ b/de-de/bash-de.html.markdown @@ -157,7 +157,7 @@ echo "#helloworld" | cat > output.out echo "#helloworld" | tee output.out >/dev/null # Löschen der Hilfsdateien von oberhalb, mit Anzeige der Dateinamen -# (mit '-i' für "interactive" erfolgt für jede Date eine Rückfrage) +# (mit '-i' für "interactive" erfolgt für jede Datei eine Rückfrage) rm -v output.out error.err output-and-error.log # Die Ausgabe von Befehlen kann mit Hilfe von $( ) in anderen Befehlen verwendet weden: @@ -217,7 +217,7 @@ done function foo () { echo "Argumente funktionieren wie bei skripts: $@" - echo Und: $1 $2..." + echo "Und: $1 $2..." echo "Dies ist eine Funktion" return 0 } diff --git a/de-de/bc.html.markdown b/de-de/bc.html.markdown new file mode 100644 index 00000000..49a2878d --- /dev/null +++ b/de-de/bc.html.markdown @@ -0,0 +1,102 @@ +--- +language: bc +contributors: + - ["caminsha", "https://github.com/caminsha"] +filename: learnbc-de.bc +lang: de-de +--- +```c +/* Das is ein mehr- +zeiliger Kommentar */ +# Das ist ein (einzeiliger) Kommentar (in GNU bc). + + /*1. Variablen und Kontrollstrukturen*/ +num = 45 /* Alle Variablen speichern nur Doubles und es ist + nicht möglich String-Konstanten direkt zu speichern */ +num = 45; /* Es kann nach jedem Statement ein optionales Semikolon + hinzugefügt werden */ +/* Blöcke werden mit den Operatoren {} (ähnlich wie in C) bezeichnet */ +while(num < 50) { + num += 1 /* äquivalent zu num=num+1. + a = a Op b ist äquivalent zu a Op= b*/ +} +/* Ausserdem gibt es ++ (Inkrement) und -- (Dekrement) Operatoren */ +/* Es gibt 3 spezielle Variablen: +scale: definiert die Anzahl Nachkommastellen +ibase: definiert die Basis der Eingabe +obase: definiert die Basis der Ausgabe*/ +/*Wenn-Bedingungen:*/ +hour = read() /*Eingabe einer Zahl*/ + +if(hour < 12) { /*Operatoren sind genau wie in C*/ + print "Guten Morgen\n" /*"print" Gibt Strings oder Variablen + mit einem Komma separiert aus.*/ +} else if(hour == 12) { + print "Hallo\n" + /* Escape-Sequenzen starten mite einem \ in einem String. + Um Escape-Sequenzen klarer zu machen, ist hier eine vereinfachte + Liste, welche in bc funktioneren.: + \b: Backspace + \c: carriage return + \n: Zeilenumbruch + \t: Tab + \\: Backslash*/ +} else { + /* Standardmässig sind Variablen global. */ + thisIsGlobal = 5 + /*Variablen können lokal gemacht werden. Benutze das Schlüsselwort "auto" + in einer Funktion.*/ +} + +/* Jede Variable hat als Voreinstellung den Wert 0. */ +num = blankVariable /*num wurde auf 0 gesetzt.*/ + +/*Wie in C ist nur 0 falsch.*/ +if(!num) {print "false\n"} + +/*Im Gegensatz zu C hat bc den Ternäroperator ?: nicht. Zum Beispiel +führt dieser Codeblok zu einem Fehler: +a = (num) ? 1 : 0 +Jedoch kann dies simuliert werden:*/ +a = (num) && (1) || (0) /*&& ist das UND, || ist das ODER*/ + +/*For-Schleifen*/ +num = 0 +for(i = 1; i <= 100; i++) {/*Gleich wie die For-Schleife in C*/ + num += i +} + + /*2.Funktionen und Arrays*/ +define fac(n) { /*Definiere eine Funktion mit define*/ + if(n == 1 || n == 0) { + return 1 /*Gebe einen Wert zurück*/ + } + return n * fac(n - 1) /*Rekursion ist möglich*/ +} + +/*Closures und anonyme Funktionen sind nicht möglich */ + +num = fac(4) /*24*/ + +/*Dies ist ein Beispiel von lokalen Variabeln.*/ +define x(n) { + auto x + x = 1 + return n + x +} +x(3) /*4*/ +print x /*Es stellt sich heraus, dass x ausserhalb der Funktion nicht + zugänglich ist.*/ +/*Arrays sind äquivalent zu C Arrays.*/ +for(i = 0; i <= 3; i++) { + a[i] = 1 +} +/*Greife wie folgt darauf zu:*/ +print a[0], " ", a[1], " ", a[2], " ", a[3], "\n" +quit /* Füge diese Codezeile hinzu, um sicherzustellen, dass +das Programm beendet. Diese Codezeile ist optional.*/ +``` +Viel Spass mit diesem einfachen Rechner! (Oder dieser Programmiersprache, um exakt zu sein.) + +Das ganze Programm wurde in GNU bc geschrieben. Um es auszuführen, benutze ```bc learnbc.bc```. + diff --git a/de-de/c++-de.html.markdown b/de-de/c++-de.html.markdown new file mode 100644 index 00000000..87e75ad6 --- /dev/null +++ b/de-de/c++-de.html.markdown @@ -0,0 +1,1158 @@ +--- +language: c++ +filename: learncpp-de.cpp +contributors: + - ["Steven Basart", "http://github.com/xksteven"] + - ["Matt Kline", "https://github.com/mrkline"] + - ["Geoff Liu", "http://geoffliu.me"] + - ["Connor Waters", "http://github.com/connorwaters"] + - ["Ankush Goyal", "http://github.com/ankushg07"] + - ["Jatin Dhankhar", "https://github.com/jatindhankhar"] + - ["Maximilian Sonnenburg", "https://github.com/LamdaLamdaLamda"] + - ["caminsha", "https://github.com/caminsha"] +lang: de-de +--- + +C++ ist eine Systemprogrammiersprache die, + +[laut dem Begründer Bjarne Stroustrup](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote) +entworfen wurde um, + +- "besseres C" zu sein +- Datenabstraktion zu unterstützen +- Objektorientierung zu unterstützen +- generische Programmierung zu unterstützen + +Durch seine Syntax kann sie durchaus schwieriger und komplexer als neuere Sprachen sein. + +Sie ist weit verbreitet, weil sie in Maschinen-Code kompiliert, welcher direkt vom Prozessor ausgeführt +werden kann und somit eine strikte Kontrolle über die Hardware bietet und gleichzeitig +High-Level-Features wie generics, exceptions und Klassen enthält. + +Diese Kombination aus Geschwindigkeit und Funktionalität bildet C++ und ist eine der +weitverbreitesten Programmiersprachen. + +```c++ +////////////////// +// Vergleich zu C +////////////////// + +// C ist fast eine Untermenge von C++ und teilt sich grundsätzlich die +// Syntax für Variablen Deklarationen, primitiven Typen und Funktionen. + +// Wie in C ist der Programmeinsprungpunkt eine Funktion, welche "main" genannt wird und +// einen Integer als Rückgabetyp besitzt. + +// Dieser Wert fungiert als Beendigungsstatus des Programms. +// Siehe: https://de.wikipedia.org/wiki/Return_Code für weitere Informationen +int main(int argc, char** argv) +{ + // Kommandozeilen Argumente werden genauso wie in C über argc und argv übergeben + // argc entspricht der Anzahl von Argumenten und argv ist ein Array von C-style + // strings (char*), welche die Argumente repräsentieren. + // Das erste Argument ist der Name des Programms, welches aufgerufen wird. + // Argc und argv können, wenn nicht benötigt, weg gelassen werden, indem + // die Funktionssignatur "int main()" verwendet wird. + + // Ein Rückgabewert von 0 repräsentiert die erfolgreiche Ausführung. + return 0; +} + +// C++ unterscheidet sich in einigen Punkten von C: + +// In C++ sind Zeichen-Literale char´s +sizeof('c') == sizeof(char) == 1 + +// In C sind Zeichen-Literale int´s +sizeof('c') == sizeof(int) + +// C++ verwendet striktes prototyping +void func(); // Funktion ohne Argumente + +// In C +void func(); // Funktion mit beliebiger Anzahl von Argumenten + +// Verwende nullptr, anstatt von NULL!!! +int* ip = nullptr; + +// C standard header sind in C++ verfügbar. +// C header enden mit .h, während +// C++ header das Präfix "c" besitzen und kein ".h" Suffix verwenden. + +// Die C++ Standard Version: +#include <cstdio> + +// Die C Standard Version: +#include <stdio.h> + +int main() +{ + printf("Hello, world!\n"); + return 0; +} + +/////////////////////// +// Funktionsüberladung +/////////////////////// + +// C++ unterstützt Funktionsüberladung +// Jede Funktion kann unterschiedliche Parameter erhalten. +void print(char const* myString) +{ + printf("String %s\n", myString); +} + +void print(int myInt) +{ + printf("My int is %d", myInt); +} + +int main() +{ + print("Hello"); // Wird aufgelöst zu "void print(const char*)" + print(15); // Wird aufgelöst zu "void print(int)" +} + +///////////////////////////// +// Standard Funktionsargumente +///////////////////////////// + +// Argumente können per Standard für eine Funktion gesetzt werden, +// wenn diese beim Aufruf nicht bereitgestellt werden. +void doSomethingWithInts(int a = 1, int b = 4) +{ + // führe Anweisungen mit "int´s" aus. +} + +int main() +{ + doSomethingWithInts(); // a = 1, b = 4 + doSomethingWithInts(20); // a = 20, b = 4 + doSomethingWithInts(20, 5); // a = 20, b = 5 +} + +// Standard-Argumente müssen am Ende der Liste der Argumente stehen. +void invalidDeclaration(int a = 1, int b) // Fehler! +{ +} + + +///////////// +// Namespaces (Namensräume) +///////////// + +// Namespaces stellen einen getrennten Gültigkeitsbereich für Variablen, +// Funktionen und andere Deklarationen zur Verfügung. +// Namespaces können geschachtelt werden. +namespace First +{ + namespace Nested + { + void foo() + { + printf("This is First::Nested::foo\n"); + } + } // Ende des Namespace "Nested" +} // Ende des Namespace "First" + +namespace Second +{ + void foo() + { + printf("This is Second::foo\n"); + } +} + +void foo() +{ + printf("This is global foo\n"); +} + +int main() +{ + // Fügt alle Symbole aus dem namespace Second in den aktuellen Gültigkeitsbereich (scope). + // "foo()" wird nun nicht länger funktionieren, da es nun doppeldeutig ist, ob foo aus + // dem namespace foo oder darüberliegenden aufgerufen wird. + using namespace Second; + + Second::foo(); // Gibt "This is Second::foo" aus. + First::Nested::foo(); // Gibt "This is First::Nested::foo" aus. + ::foo(); // Gibt "This is global foo" aus. +} + +/////////////// +// Eingabe/Ausgabe +/////////////// + +// C++ verwendet für die Eingabe und Ausgabe streams. +// cin, cout und cerr repräsentieren stdin, stdout und stderr. +// << ist der Einfügeoperator und >> ist der Extraktionsoperator. + +#include <iostream> // Include für Eingabe/Ausgabe (I/O) streams + +using namespace std; // Streams befinden sich im std namespace (standard library) + +int main() +{ + int myInt; + + // Ausgabe auf stdout (oder Terminal/Bildschirm) + cout << "Enter your favorite number:\n"; + + // Empfängt Eingabe + cin >> myInt; + + // cout kann ebenfalls formatiert werden + cout << "Your favorite number is " << myInt << "\n"; + // Gibt "Your favorite number is <myInt>" aus + + cerr << "Used for error messages"; +} + +////////// +// Zeichenketten (Strings) +////////// + +// Strings in C++ sind Objekte und haben diverse member-functions +#include <string> + +using namespace std; // Strings sind ebenfalls im namespace std (Standard Bibliothek) + +string myString = "Hello"; +string myOtherString = " World"; + +// + wird für das Anhängen von strings verwendet. +cout << myString + myOtherString; // "Hello World" + +cout << myString + " You"; // "Hello You" + +// C++ strings sind mutable. +myString.append(" Dog"); +cout << myString; // "Hello Dog" + + +///////////// +// Referenzen +///////////// + +// Zusätzlich zu Pointern, wie jene in C. +// C++ besitzt _Referenzen_. +// Diese sind Pointer-Typen, welche nicht erneut zugewiesen werden können +// und nicht Null sein können. +// Sie besitzen den selben Syntax wie Variablen. +// Für die Dereferenzierung ist kein * notwendig und +// & (die Adresse) wird nicht für die Zuweisung verwendet. + +using namespace std; + +string foo = "I am foo"; +string bar = "I am bar"; + + +string& fooRef = foo; // Erzeugt eine Referenz auf foo. +fooRef += ". Hi!"; // Verändert foo durch die Referenz +cout << fooRef; // Gibt "I am foo. Hi!" aus. + + +// Weist "fooRef" nicht erneut zu. Dies ist dasselbe, wie "foo = bar" und +// foo == "I am bar" +// nach dieser Zeile +cout << &fooRef << endl; // Gibt die Adresse von foo aus +fooRef = bar; +cout << &fooRef << endl; // Gibt ebenfalls die Adresse von foo aus +cout << fooRef; // Gibt "I am bar" aus + +// Die Adresse von fooRef verbleibt die selbe, sie verweist immer noch auf foo + +const string& barRef = bar; // Erzeugt konstante Referenz auf bar. +// Wie in C, können konstante Werte ( und Pointer bzw. Referenzen) nicht verändert werden. + +barRef += ". Hi!"; // Fehler: konstante Referenzen können nicht verändert werden. + +// Hinweis: bevor wir genauer Referenzen besprechen, schauen wir uns zuerst ein Konzept an, +// welches als "temporäres Objekt" bezeichnet wird. Gehen wir von folgenden Code aus: +string tempObjectFun() { ... } +string retVal = tempObjectFun(); + +// Was passiert nun in der zweiten Zeile: +// - ein String Objekt wird von "tempObjectFun" zurückgegeben +// - ein neuer String wird mit dem zurückgegebenen Objekt als Argument für den Konstruktor erzeugt. +// - das zurückgegebene Objekt wird zerstört +// Das zurückgegbene Objekt wird temporäres Objekt genannt. Temporäre Objekte werden erzeugt +// wann immer eine Funktion ein Objekt zurückgibt. Zerstört werden diese am Ende der Auswertung des Ausdrucks +// (dies schreibt der Standard vor, aber Compiler sind berechtigt dieses Verhalten zu ändern. Siehe "return value optimization" +// für Details). Wie in diesem Code: +foo(bar(tempObjectFun())) + +// Nehmen wir an, foo und bar existieren. Das Objekt wird von "tempObjectFun" zurückgegeben, +// wird an bar übergeben und ist zerstört bevor foo aufgerufen wird. + +// Zurück zu Referenzen. Die Annahme, dass die "am Ende des Ausdrucks" Regel gültig ist, +// wenn das temporäre Objekt an eine konstante Referenz gebunden ist, ist der Fall, wenn die Lebensdauer +// auf den aktuellen Gültigkeitsbereich erweitert wird. + +void constReferenceTempObjectFun() { + // constRef erhält das temporäre Objekt und ist gültig bis ans Ende der Funktion + const string& constRef = tempObjectFun(); + ... +} + +// Eine andere Art von Referenzen wurde in C++11 eingeführt und ist speziell für +// temporäre Objekte. Es ist nicht möglich Variablen des Typs zu besitzen, aber +// Vorrechte bei der Auflösung zu besitzen. + +void someFun(string& s) { ... } // Reguläre Referenz +void someFun(string&& s) { ... } // Referenz auf ein temporäres Objekt + +string foo; +someFun(foo); // Ruft die Funktion mit der regulären Referenz auf +someFun(tempObjectFun()); // Ruft die Funktion mit der temporären Referenz auf + +// Zum Beispiel existieren diese zwei Varianten von Konstruktoren für +// std::basic_string: +basic_string(const basic_string& other); +basic_string(basic_string&& other); + +// Nehmen wir an, wir erzeugen einen neuen String eines temporären Objekts (welches später +// zerstört wird), hierbei existiert ein effizienterer Konstruktor. Dieses Konzept wird +// als "move semantics" bezeichnet (bewegen eines Objekts in ein anderes in C++). + +///////////////////// +// Enumerations (Aufzählungstypen) +///////////////////// + +// Enums sind eine einfachere Art und Weise einen Wert einer Konstante zu zuweisen. +// Häufig wird dies verwendet, um den Code lesbarer zu gestalten bzw. zu visualisieren. +enum ECarTypes +{ + Sedan, + Hatchback, + SUV, + Wagon +}; + +ECarTypes GetPreferredCarType() +{ + return ECarTypes::Hatchback; +} + +// Mit C++11 existiert eine einfache Möglichkeit einem Typ dem Enum zuzuweisen. Dies +// kann durchaus sinnvoll bei der Serialisierung von Daten sein, oder bei der Konvertierung +// zwischen Typen bzw. Konstanten. +enum ECarTypes : uint8_t +{ + Sedan, // 0 + Hatchback, // 1 + SUV = 254, // 254 + Hybrid // 255 +}; + +void WriteByteToFile(uint8_t InputValue) +{ + // Serialisierung von "InputValue" in eine Datei +} + +void WritePreferredCarTypeToFile(ECarTypes InputCarType) +{ + // Das enum wird implizit zu einem "uint8_t" konvertiert. Bedingt dadurch, dass + // es sich um ein "enum" handelt. + WriteByteToFile(InputCarType); +} + +// Nicht immer ist es gewünscht, dass enum´s zu einem Integer oder zu einem anderen +// enum umgewandelt werden. Daher ist es möglich eine enum-Klasse zu erzeugen, welche +// nicht implizit umgewandelt wird. +enum class ECarTypes : uint8_t +{ + Sedan, // 0 + Hatchback, // 1 + SUV = 254, // 254 + Hybrid // 255 +}; + +void WriteByteToFile(uint8_t InputValue) +{ + // Serialisierung von InputValue in eine Datei +} + +void WritePreferredCarTypeToFile(ECarTypes InputCarType) +{ + // Wird nicht kompilieren, da "ECarTypes" ein "uint8_t" ist, da das enum + // als "enum class" deklariert wurde! + WriteByteToFile(InputCarType); +} + +////////////////////////////////////////// +// Klassen und objekorientierte Programmierung +////////////////////////////////////////// + +// Erstes Beispiel einer Klasse +#include <iostream> + +// Deklaration einer Klasse. +// Klassen werden üblicherweise im header (.h oder .hpp) deklariert. +class Dog +{ + // Member Variablen und Funktionen sind private per default (standard). + std::string name; + int weight; + +// Alle nachfolgenden member sind "public" bis +// "private:" oder "protected:" auftritt. +public: + + // Standard Konstruktor + Dog(); + + // Member-Funktionsdeklaration (Implementierung folgt). + // Bemerkung: std::string statt der Verwendung von namespace std; + // "using namespace" sollte niemals in einem header verwendet werden. + void setName(const std::string& dogsName); + + void setWeight(int dogsWeight); + + // Funktionen, die Objekte nicht ändern, sollten mit const deklariert werden. + // Funktionen müssen explizit als "virtual" deklariert werden, um in einer + // abgeleiteten Klassen überschrieben zu werden. + // Aus performance Gründen sind Funktionen nicht per default virtual. + virtual void print() const; + + // Funktionen können ebenfalls im class body definiert werden. + // Derart definierte Funktionen sind automatisch "inline". + void bark() const { std::cout << name << " barks!\n"; } + + // Neben Konstruktoren, bietet C++ Destruktoren. + // Diese werden aufgerufen, wenn ein Objekt freigegeben wird oder + // seinen Wertebereich verlässt. + // Dies ermöglicht mächtige Paradigmen, wie auch RAII. + // Destruktoren sollten virtual sein, wenn eine Klasse von ihr + // abgeleitet wird. Ist dieser nicht virtual, dann wird der + // Destruktor der abgeleiteten Klasse nicht aufgerufen, insofern + // das Objekt durch eine Referenz/Pointer der Basisklasse entfernt wird. + virtual ~Dog(); + +}; // Ein Semikolon schließt die Definition der Klasse ab. + +// Klassen-Member-Funktionen sind üblicherweise in der .cpp Datei implementiert. +Dog::Dog() +{ + std::cout << "A dog has been constructed\n"; +} + +// Objekte sollten als Referenz übergeben werden und wenn diese nicht +// verändert werden sollen, sollte das Objekt als const Referenz übergeben werden. +void Dog::setName(const std::string& dogsName) +{ + name = dogsName; +} + +void Dog::setWeight(int dogsWeight) +{ + weight = dogsWeight; +} + +// "Virtual" wird nur bei der Deklaration benötigt und nicht bei der Definition. +void Dog::print() const +{ + std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; +} + +Dog::~Dog() +{ + std::cout << "Goodbye " << name << "\n"; +} + +int main() +{ + Dog myDog; // Ausgabe: "A dog has been constructed" + myDog.setName("Barkley"); + myDog.setWeight(10); + myDog.print(); // Ausgabe: "Dog is Barkley and weighs 10 kg" + return 0; +} // Ausgabe: "Goodbye Barkley" + +// Diese Klasse erbt alles was public bzw. protected ist von der Dog-Klasse +// und darüber hinaus auch private Methoden/Attribute, jedoch kann auf diese +// nicht direkt zugegriffen werden. Lediglich über public/procted getter/setter. +class OwnedDog : public Dog { + +public: + void setOwner(const std::string& dogsOwner); + + // Überschreibt das Verhalten der "print" Funktion für alle "OwnedDogs". + // Siehe: http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping + // für eine grundlegende Einführung in "Subtype Polymorphismus". + // Das "override" Schlüsselwort ist optional, aber stellt sicher, dass die + // Methode der Basisklasse tatsächlich überschrieben wurde. + void print() const override; + +private: + std::string owner; +}; + +// Die zugehörige .cpp Datei +void OwnedDog::setOwner(const std::string& dogsOwner) +{ + owner = dogsOwner; +} + +void OwnedDog::print() const +{ + Dog::print(); // Ruft die "print" Funktion der Basisklasse auf. + std::cout << "Dog is owned by " << owner << "\n"; + // Ausgaben: "Dog is <name> and weights <weight>" + // "Dog is owned by <owner>" +} + +////////////////////////////////////////// +// Initialisierung und Operatorüberladung +////////////////////////////////////////// + +// In C++ können Operatoren wie: +, -, *, / etc. überladen werden. +// Dies wird umgesetzt, indem eine entsprechende Funktion definiert wird, +// welche immer dann aufgerufen wird, sobald der Operator verwendet wird. +#include <iostream> +using namespace std; + +class Point +{ +public: + // Member Variablen können mit einem default Wert initialisiert werden. + double x = 0; + double y = 0; + + // Definition des Standard Konstruktor, welcher nichts tut + // außer den Punkt auf den default Wert (0,0) zu setzen. + Point() { }; + + // Die nachfolgende Syntax ist bekannt als "initialization list" + // und ist eine gängige Art Klassen-Member zu initialisieren. + Point (double a, double b) : + x(a), + y(b) + { /* Außschließliche Initialisierung der Werte */ } + + // Überladung des "+" Operator. + Point operator+(const Point& rhs) const; + + // Überladung des "+=" Operator + Point& operator+=(const Point& rhs); + + // Sinnhaft wäre es an dieser Stelle den "-" und "-=" Operator + // ebenfalls zu überladen. +}; + +Point Point::operator+(const Point& rhs) const +{ + // Erzeugung eines neuen Punkts, welcher die Summe aus sich + // selbst und "rhs" bildet + return Point(x + rhs.x, y + rhs.y); +} + +Point& Point::operator+=(const Point& rhs) +{ + x += rhs.x; + y += rhs.y; + return *this; +} + +int main () +{ + Point up (0,1); + Point right (1,0); + + // Ruft den + Operator mit den entsprechenden Parametern auf. + Point result = up + right; + // Ausgabe: "Result is upright (1,1)" + cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; + return 0; +} + +///////////////////// +// Templates +///////////////////// + +// Templates in C++ werden in erster Linie dafür verwendet generisch zu programmieren. +// Sie unterstützen explizite und partielle Spezialisierung und darüber hinaus können +// sie für funktionale Klassen verwendet werden. +// Tatsächlich bilden Templates die Turing-Vollständigkeit +// (universelle Programmierbarkeit) ab. + + +// Zu Beginn ein einführendes Beispiel der generischen Programmierung. +// Die Definition einer Klasse bzw. Funktion, welche mit dem Typ T parametriert wird. +template<class T> +class Box +{ +public: + // T repräsentiert an dieser Stelle einen beliebigen Typen. + void insert(const T&) { ... } +}; + +// Während der Kompilierung generiert der Compiler Kopien für jedes Template, wobei +// hierbei die Parameter substituiert werden. Somit muss bei jedem Aufruf die gesamte +// Definition der Klasse zur Verfügung stehen. Aus diesem Grund wird ein Template +// komplett im header definiert. + +// Erzeugung einer Template-Klasse auf dem Stack: +Box<int> intBox; + +// eine der zu erwartenden Verwendungen: +intBox.insert(123); + +// Verschachtelungen von Templates sind möglich. +Box<Box<int> > boxOfBox; +boxOfBox.insert(intBox); + +// Bis C++11 war es erforderlich ein Leerzeichen zwischen '>' einzufügen, +// andernfalls wurde es als '>>' geparsed (right shift). + +// Manchmal ist folgende Notation anzutreffen: +// template<typename T> +// Das 'class' Schlüsselwort und das 'typename' Schlüsselwort +// sind fast identisch hinsichtlich der Funktionalität. Weitere +// Informationen auf: http://en.wikipedia.org/wiki/Typename + +// Eine Template-Funktion: +template<class T> +void barkThreeTimes(const T& input) +{ + input.bark(); + input.bark(); + input.bark(); +} + +// Hierbei ist zu beachten, dass an dieser Stelle nichts über den Typen des Parameters +// definiert wurde. Der Compiler wird bei jedem Aufruf bzw. jeder Erzeugung den Typen +// prüfen. Somit funktioniert die zuvor definierte Funktion für jeden Typ 'T', die die +// const Methode 'bark' implementiert hat. + +Dog fluffy; +fluffy.setName("Fluffy") +barkThreeTimes(fluffy); // Gibt "Fluffy barks" dreimal aus. + +// Template Parameter müssen keine Klassen sein. +template<int Y> +void printMessage() +{ + cout << "Learn C++ in " << Y << " minutes!" << endl; +} + +// Des Weiteren können Templates aus Effizienzgründen genauer spezifiziert werden. +// Selbstverständlich sind reale Probleme, welche genauer spezifiziert werden, nicht +// derart trivial. Auch wenn alle Parameter explizit definiert wurden, muss die +// Funktion oder Klasse als Template deklariert werden. +template<> +void printMessage<10>() +{ + cout << "Learn C++ faster in only 10 minutes!" << endl; +} + +printMessage<20>(); // Gibt "Learn C++ in 20 minutes!" aus. +printMessage<10>(); // Gibt "Learn C++ faster in only 10 minutes!" aus. + + +///////////////////// +// Ausnahme Behandlungen (Exception-Handling) +///////////////////// + +// Die Standard Bibliothek bietet einige exceptions. +// Siehe: http://en.cppreference.com/w/cpp/error/exception. +// Grundsätzlich können alle Typen als exception geworfen werden. +#include <exception> +#include <stdexcept> + +// Alle exceptions, die in dem "try" Block geworfen werden, können mittels +// "catch" abgefangen werden. +try +{ + // exceptions sollten nicht auf dem heap mithilfe + // von "new" allokiert werden. + throw std::runtime_error("A problem occurred"); +} + +// Exceptions sollten als const Referenz abgefangen werden +// insofern diese Objekte sind. +catch (const std::exception& ex) +{ + std::cout << ex.what(); +} + +// Abfangen aller Exceptions, welche zuvor nicht abgefangen wurden. +catch (...) +{ + std::cout << "Unknown exception caught"; + throw; // Erneutes werfen der exception +} + +/////// +// RAII +/////// + +// RAII steht für "Resource Acquisition Is Initialization". +// Oft wird dies als eines der wichtigsten Paradigmen in C++ betrachtet. +// RAII beschreibt das Konzept, dass der Konstruktor für ein Objekt +// die Ressourcen akquiriert und der Destruktor diese freigibt. + +// Zum Verständnis, warum dies sinnvoll ist, nachfolgend +// ein einführendes Beispiel: +void doSomethingWithAFile(const char* filename) +{ + // Wir nehmen an, dass nichts schiefgehen wird. + FILE* fh = fopen(filename, "r"); // Öffnen der Datei im read-mode. + + doSomethingWithTheFile(fh); + doSomethingElseWithIt(fh); + + fclose(fh); // Schließen des file-handle. +} + +// Unglücklicherweise ist die Fehlerbehandlung äußerst kompliziert. +// Sollte fopen fehlschlagen und "doSomethingWithTheFile" bzw. +// "doSomethingElseWithIt", geben diese einen Fehlercode zurück. +// (Exceptions sind eine bevorzugte Möglichkeit Fehler abzufangen +// , allerdings bei einigen Programmierern, besonders solchen die einen C +// background besitzen, ein unbeliebtes Mittel zur Fehlerbehandlung). +// Nun müssen wir jeden Aufruf auf mögliche auftretende Fehler überprüfen. +bool doSomethingWithAFile(const char* filename) +{ + FILE* fh = fopen(filename, "r"); // Öffnet die Datei im read-mode + if (fh == nullptr) // Der Pointer ist bei einem Fehler NULL . + return false; // Benachrichtigt den Aufrufer über den Fehler. + + // Wir nehmen an, dass jede Funktion false zurückgibt, in einem Fehlerfall + if (!doSomethingWithTheFile(fh)) + { + fclose(fh); // File handle schließen. + return false; // Fehler "melden". + } + + if (!doSomethingElseWithIt(fh)) + { + fclose(fh); // File handle schließen. + return false; // Fehler "melden". + } + + fclose(fh); // File handle schließen. + return true; // Erfolg "melden". +} + +// C-Programmierer handhaben dies häufig durch goto-Anweisungen: +bool doSomethingWithAFile(const char* filename) +{ + FILE* fh = fopen(filename, "r"); + if (fh == nullptr) + return false; + + if (!doSomethingWithTheFile(fh)) + goto failure; + + if (!doSomethingElseWithIt(fh)) + goto failure; + + fclose(fh); // File handle schließen. + return true; // Erfolg "melden". + +failure: + fclose(fh); + return false; // Fehler "melden". +} + +// Insofern Funktionen Fehler durch exceptions indizieren, +// ist dies "sauberer", aber immer noch suboptimal. +void doSomethingWithAFile(const char* filename) +{ + FILE* fh = fopen(filename, "r"); // Öffnet die Datei im read-mode + if (fh == nullptr) + throw std::runtime_error("Could not open the file."); + + try + { + doSomethingWithTheFile(fh); + doSomethingElseWithIt(fh); + } + catch (...) + { + // Im Fehlerfall sollte sichergestellt sein, dass die + // Datei geschlossen wird. + fclose(fh); + throw; // Erneutes werfen der exception + } + + fclose(fh); // Schließen der Datei +} + +// Folgendes ist mit der C++ file stream Klasse (fstream) zu vergleichen. +// fstream verwendet den Destruktor, um die Datei zu schließen. +// Der obige Destruktor wird automatisch aufgerufen, sobald das Objekt +// den Gültigkeitsbereich verlässt. +void doSomethingWithAFile(const std::string& filename) +{ + // ifstream entspricht der Kurzform von "input file stream". + std::ifstream fh(filename); // Öffnen der Datei + + doSomethingWithTheFile(fh); + doSomethingElseWithIt(fh); + +} // Die Datei wird automatisch vom Destruktor geschlossen. + +// Diese Vorgehensweise bietet massive Vorteile: +// 1. Egal was passiert, die Ressource (das Datei-Handle) wird aufgelöst, +// insofern der Destruktor korrekt beschrieben wurde. Es ist möglich +// zu vergessen das Datei-Handle zu schließen, was zu einem "leak" der +// entsprechenden Ressource führt. +// 2. Der Code selbst ist wesentlich "sauberer". +// Der Destruktor wird das Datei-Handle im Hintergrund schließen und der +// Programmierer muss sich darum keinerlei Sorgen machen. +// 3. Der Code ist "exception sicher". +// Egal wo die exception geworfen wird, das Aufräumen wird definitiv vollzogen. + +// Der gesamte idiomatische C++ Code verwendet RAII für alle Ressourcen. +// Weitere Beispiele: +// - Speicher verwenden "unique_ptr" und "shared_ptr". +// - Container - verkettete Listen (linked list), vector (selbst organisierende +// Arrays), hash maps, etc., entfernen deren Inhalt, wenn diese außerhalb des +// Gültigkeitsbereichs laufen. +// - Mutex´s verwenden lock_guard und unique_lock. + +///////////////////// +// Container +///////////////////// + +// Die Container der Standard template Bibliothek beinhaltet einige vordefinierte Templates. +// Diese verwalten die Speicherbereiche für die eigenen Elemente und stellen Member-Funktionen +// für den Zugriff und die Manipulation bereit. + +// Beispielhafte Container: + +// Vector (dynamisches array) +// Erlaubt das Definieren von Arrays oder Listen zur Laufzeit +#include <vector> +string val; +vector<string> my_vector; // Initialisierung des Vectors. +cin >> val; +my_vector.push_back(val); // Fügt den Wert "val" zum Vektor "my_vector" hinzu. +my_vector.push_back(val); // Fügt den Wert "val" zum Vektor "my_vector" hinzu (nun zwei Elemente). + +// Für die Iteration über Vektoren stehen zwei Methodiken zu Verfügung: +// Entweder die klassische Iteration über den Index: +for (int i = 0; i < my_vector.size(); i++) +{ + cout << my_vector[i] << endl; // Zugriff auf die Elemente des Vektors über den [] Operator +} + +// Oder die Verwendung von Iteratoren: +vector<string>::iterator it; // Initialisierng des Iterators. +for (it = my_vector.begin(); it != my_vector.end(); ++it) +{ + cout << *it << endl; +} + +// Set (Mengen) +// Sets sind Container, welche einzigartige Elemente beinhalten die einer +// spezifischen Ordnung folgen. + +#include<set> +set<int> ST; // Initialisierung des Sets mit einem Integer Datentyp. +ST.insert(30); // Einfügen des Werts 30 in das Set ST +ST.insert(10); // Einfügen des Werts 10 in das Set ST +ST.insert(20); // Einfügen des Werts 20 in das Set ST +ST.insert(30); // Einfügen des Werts 30 in das Set ST +// Folgende Elemente befinden sich nun in dem Set: +// 10 20 30 + +// Entfernen eines Elements: +ST.erase(20); + +// Set ST: 10 30 +// Für das iterieren verwenden wir Iteratoren: +set<int>::iterator it; + +for(it=ST.begin();it<ST.end();it++) +{ + cout << *it << endl; +} + +// Ausgabe: +// 10 +// 30 + +// Zum leeren des gesamten Containers wird die Methode +// Container._name.clear() verwendet. +ST.clear(); +cout << ST.size(); // Ausgabe der Set-Größe + +// Ausgabe: 0 + +// Bemerkung: für mehrdeutige Elemente werden multisets verwendet. +// Für hash-Sets sollten unordered_set´s verwendet werden, da diese +// wesentlich effizienter sind, allerdings keiner Ordnung folgen. +// Verfügbar sind diese Features ab C++11. + +// Map +// Maps speichern Elemente, welche einer Kombination aus "Key" +// und "Value" folgen. + +#include<map> +map<char, int> mymap; // Initialisierung der Map: char -> Key, int -> Value. + +mymap.insert(pair<char,int>('A',1)); // Einfügen des Werts "1" für den Key "A". + +mymap.insert(pair<char,int>('Z',26)); // Einfügen des Werts "26" für den Key "Z". + +// Das Iterieren über Maps: +map<char,int>::iterator it; +for (it=mymap.begin(); it!=mymap.end(); ++it) + std::cout << it->first << "->" << it->second << '\n'; + +// Ausgabe: +// A->1 +// Z->26 + +// Für das Finden des dazugehörigen Value des Keys. +it = mymap.find('Z'); +cout << it->second; + +// Ausabe: 26 + +// Bemerkung: für "hash maps" sollten die "unordered_map´s" verwendet werden. Diese +// sind effizienter und benötigen keine Reihenfolge. "unordered_maps" sind ab +// C++11 verfügbar. + +// Container für nicht-primitive Datentypen benötigen Vergleichsfunktionen im Objekt selbst, +// oder als Funktionspointer. Primitive Datentypen besitzen default-Vergleichsfunktionen. +// Allerdings können diese überschrieben werden. +class Foo +{ +public: + int j; + Foo(int a) : j(a) {} +}; + +struct compareFunction +{ + bool operator()(const Foo& a, const Foo& b) const + { + return a.j < b.j; + } +}; + +// Folgender Code ist nicht valide, könnte aber von einigen Compilern +// als valide angesehen werden: +// std::map<Foo, int> fooMap; +std::map<Foo, int, compareFunction> fooMap; +fooMap[Foo(1)] = 1; +fooMap.find(Foo(1)); // Wahr + + +/////////////////////////////////////// +// Lambda Ausdrücke (C++11 und höher) +/////////////////////////////////////// + +// Lambdas sind eine gängige Methodik, um anonyme Funktionen an dem +// Ort der Verwendung zu definieren. Darüber hinaus auch bei der +// Verwendung von Funktionen als Argument einer Funktion. + +// Nehmen wir an, es soll ein Vektor von "pairs" (Paaren) mithilfe +// des zweiten Werts des "pairs" sortiert werden. + +vector<pair<int, int> > tester; +tester.push_back(make_pair(3, 6)); +tester.push_back(make_pair(1, 9)); +tester.push_back(make_pair(5, 0)); + +// Übergabe des Lambda-Ausdrucks als drittes Argument für die nachfolgende Sortierfunktion. +sort(tester.begin(), tester.end(), [](const pair<int, int>& lhs, const pair<int, int>& rhs) +{ + return lhs.second < rhs.second; +}); + +// Beachte die Syntax von Lambda-Ausdrücken. +// Die [] im Lambda Ausdruck werden für die Variablen verwendet. +// Diese so genannte "capture list" definiert, was außerhalb des Lambdas, +// innerhalb der Funktion verfügbar sein soll und in welcher Form. +// Dies kann folgendes sein: +// 1. ein Wert [x] +// 2. eine Referenz [&x] +// 3. eine beliebige Variable, welche sich im Gültigkeitsbereich durch +// die Referenz [&] befindet. +// 4. wie bei 3. aber mithilfe des Werts [=] +// Beispiel: + +vector<int> dog_ids; + +for(int i = 0; i < 3; i++) +{ + dog_ids.push_back(i); +} + +int weight[3] = {30, 50, 10}; + +// Nehmen wir an wir möchten die "dog_ids" gemäß des Gewichts des Hundes sortieren. +// So sollten sich die "dog_ids" wie folgt verhalten: [2, 0, 1] + +// Hier werden Lambdas praktisch: +sort(dog_ids.begin(), dog_ids.end(), [&weight](const int &lhs, const int &rhs) +{ + return weight[lhs] < weight[rhs]; +}); + + +// Weiterführender Link über Lambda-Ausdrücke: +// http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11 + +/////////////////////////////// +// Range For (C++11 und höher) +/////////////////////////////// + +// Range-For Schleifen können verwendet werden, um über Container zu iterieren. +int arr[] = {1, 10, 3}; + +for(int elem: arr) +{ + cout << elem << endl; +} + +// Insofern "auto" verwendet wird, muss der Typ nicht weiter beachtet werden. +for(auto elem: arr) +{ + // Anweisungen ... +} + +///////////////////// +// Weiteres: +///////////////////// + +// Einige Aspekte von C++ sind für Neueinsteiger häufig überraschend (aber auch für +// C++ Veteranen). +// Der nachfolgende Abschnitt ist leider nicht vollständig: +// C++ ist eine der Sprachen, bei der es ein Leichtes ist, sich selbst ins Bein zu schießen. + +// Private-Methoden können überschrieben werden +class Foo +{ + virtual void bar(); +}; + +class FooSub : public Foo +{ + virtual void bar(); // Überschreibt Foo::bar! +}; + +// 0 == false == NULL +bool* pt = new bool; +*pt = 0; // Setzt den Wert des Pointers 'pt' auf false. +pt = 0; // Setzt 'pt' auf den "null-pointer". Keine Compiler-Warnung. + +// nullptr sollte dieses Problem nicht lösen: +int* pt2 = new int; +*pt2 = nullptr; // Kompiliert nicht. +pt2 = nullptr; // Setzt pt2 auf null. + +// Eine Ausnahme bilden bool´s. +// Dies erlaubt es "null-pointer" zu testen: if(!ptr) +// Die Konsequenz ist jedoch, dass dem nullptr ein bool zugewiesen werden kann. +*pt = nullptr; // Kompiliert auch, wenn '*pt' ein bool ist! + +// '=' != '=' != '='! +// Ruft Foo::Foo(const Foo&) auf, oder den Kopierkonstruktor +Foo f2; +Foo f1 = f2; + +// Ruft Foo::Foo(const Foo&) auf, aber kopiert lediglich den "Foo" Teil von +// "fooSub". Alle zusätzlichen Member werden verworfen. Diese eigenartige Verhalten +// wird auch "object slicing" genannt. +FooSub fooSub; +Foo f1 = fooSub; + +// Ruft Foo::operator=(Foo&) oder eine andere Variante auf. +Foo f1; +f1 = f2; + +/////////////////////////////////////// +// Tuple (C++11 und höher) +/////////////////////////////////////// + +#include<tuple> + +// Konzeptionell sind Tupel alten Datenstrukturen sehr ähnlich, allerdings haben diese keine +// bezeichneten Daten-Member, sondern werden durch die Reihenfolge angesprochen. + +// Erstellen des Tupels und das Einfügen eines Werts. +auto first = make_tuple(10, 'A'); +const int maxN = 1e9; +const int maxL = 15; +auto second = make_tuple(maxN, maxL); + +// Ausgabe der Elemente des "first" Tuple. +cout << get<0>(first) << " " << get<1>(first) << "\n"; // Ausgabe : 10 A + +// Ausgabe der Elemente des "second" Tuple. +cout << get<0>(second) << " " << get<1>(second) << "\n"; // Ausgabe: 1000000000 15 + +int first_int; +char first_char; +tie(first_int, first_char) = first; +cout << first_int << " " << first_char << "\n"; // Ausgabe : 10 A + +// Tuple können auch wie folgt erzeugt werden: + +tuple<int, char, double> third(11, 'A', 3.14141); +// tuple_size gibt die Anzahl der Elemente in einem Tuple zurück. +// Als "constexpr". + +cout << tuple_size<decltype(third)>::value << "\n"; // prints: 3 + +// tuple_cat fügt die Elemente eines Tupels aneinander (in der selben Reihenfolge). + +auto concatenated_tuple = tuple_cat(first, second, third); +// concatenated_tuple wird zu = (10, 'A', 1e9, 15, 11, 'A', 3.14141) + +cout << get<0>(concatenated_tuple) << "\n"; // Ausgabe: 10 +cout << get<3>(concatenated_tuple) << "\n"; // Ausgabe: 15 +cout << get<5>(concatenated_tuple) << "\n"; // Ausgabe: 'A' + + +/////////////////////////////////// +// Logische- und Bitoperatoren +////////////////////////////////// + +// Die meisten Operatoren in C++ entsprechen denen aus anderen Sprachen + +// Logische Operatoren. +// C++ verwendet so genannte "Short-circuit" Evaluierung für Boolean-Ausdrücke. +// Das zweite Argument wird ausgeführt bzw. evaluiert, wenn das erste Argument genügt, +// um den Ausdruck zu bestimmen. + +true && false // Führt **logisches und** aus. +true || false // Führt **logisches oder** aus. +! true // Führt **logisches nicht** aus. + +// Anstelle von Symbolen können auch Schlüsselwörter verwendet werden. +true and false // Führt **logisches und** aus. +true or false // Führt **logisches oder** aus. +not true // Führt **logisches nicht** aus. + +// Bitoperationen + +// **<<** Links-Shift +// **>>** Rechts-Shift + +~4 // Führt bitweises nicht aus. +4 | 3 // Führt bitweises oder aus. +4 & 3 // Führt bitweises und aus. +4 ^ 3 // Führt bitweises xor aus. + +// Gleichwertige Schlüsselwörter: +compl 4 // Führt bitweises nicht aus. +4 bitor 3 // Führt bitweises oder aus. +4 bitand 3 // Führt bitweises und aus. +4 xor 3 // Führt bitweises xor aus. + + +``` +Weiterführende Literatur: + +* Aktuelle Sprachen-Referenz [CPP Reference](http://cppreference.com/w/cpp). +* Zusätzliches: [CPlusPlus](http://cplusplus.com). +* Grundlagen Tutorial: [TheChernoProject - C++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb). diff --git a/de-de/c-de.html.markdown b/de-de/c-de.html.markdown new file mode 100644 index 00000000..f9090518 --- /dev/null +++ b/de-de/c-de.html.markdown @@ -0,0 +1,869 @@ +--- +language: c +filename: learnc-de.c +contributors: + - ["caminsha", "https://github.com/caminsha"] +lang: de-de +--- + +Ach, C. Immer noch **die** Sprache für modernes High-Performance Computing. + +C ist wahrscheinlich die Programmiersprache mit dem niedrigsten Abstraktionsnvieau, +welche die meisten Programmierer je brauchen werden. +Die Geschwindigkeit von C ist enorm, allerdings muss man sich stets der +manuellen Speicherverwaltung bewusst sein. + + +> **Über Compiler Optionen** +> +> Standardmäßig sind `gcc` und `clang` ziemlich ruhig bezüglich Warnungen und +> Fehlern, obwohl dies sehr nützliche Informationen sein können. Es wird +> empfohlen, strengere Compiler Optionen zu verwenden. Hier sind einige empfohlene +> Standards: +> `-Wall -Wextra -Werror -O2 -std=c99 -pedantic` +> +> Da gewisse Optionen (inbesondere der C-Standard) sehr stark vom Projekt +> abhängen, lohnt es sich, wenn die unterschiedlichen Optionen genauer +> angeschaut werden. Eine Übersicht über die Compiler-Optionen findet man unter +> [diesem](https://stackoverflow.com/questions/3375697/useful-gcc-flags-for-c) Stackoverflow-Beitrag. +> +> Für weitere Informationen, was diese und weitere Optionen genau machen, +> sollte die Man-Page des C-Compilers aufgerufen werden (z.B. `man 1 gcc`). +> Alternativ kann auch online nach den unterschiedlichen Optionen gesucht werden. + +```c +// einzeilige Kommentare starten mit // - nur in C99 und später vorhanden. + +/* +mehrzeilige Kommentare sehen so aus. Diese funktionieren auch in C89 +*/ + +/* +mehrzeilige Kommentare können nicht verschachtelt werden /* Sei Vorsichtig! */ // Kommentar endet auf dieser Linie ... +*/ // ... nicht bei dieser! + +// Konstanten: #define <keyword> +// Konstanten werden laut der Konvention immer in GROSSBUCHSTABEN geschrieben +#define DAYS_IN_YEAR 365 + +// Konstanten können auch als Aufzählungskonstanten (Enums) definiert werden. +// Alle Anweisungen müssen mit einem Semikolon beendet werden. +enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; +// MON wird automatisch zu 2, TUE zu 3 etc. + +// Importiere Header-Dateien mit #include +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +// Dateien, welche zwischen <spitzen Klammern> stehen, sind Header-Dateien aus +// der C-Standard-Bibliothek. +// Für deine eigenen Header müssen Anführungszeichen verwendet werden, z.B.: +// #include "mein_header.h" + +// Funktionssignaturen werden entweder vorher in einer .h-Datei deklariert oder +// am Anfang der .c-Datei. +void function_1(); +int funkcion_2(void); + +// Es muss ein Funktionsprototyp deklariert werden vor der `main()` Funktion, +// wenn die Funktion nach der `main()` Funktion gebraucht wird. +int add_two_ints(int x1, int x2); // Funktionsprototyp +// Auch wenn der Ausdrck `int add_two_ints(int, int)` auch valid wäre, +// ist es empfohlen, dass man die Namen der Argumente hinschreibt für eine +// einfachere Analyse. + +// Der Einstiegspunkt deines Programms ist eine Funktion mit dem Namen main und +// einem Integer als Rückgabewert. +int main(void) { + // dein Programm +} + +// Die Kommandozeilenargumente, welche gebraucht werden, damit dein Programm +// läuft, werden als Argumente der `main`-Funktion mitgegeben. +// argc (argument counter) steht für die Anzahl von Argumenten. +// Der Programmname ist das erste Argument. +// argv (argument vector) ist ein Array von Zeichenarrays, welche die +// Argumente beinhaltet. +// argv[0] = Name des Programms +// argv[1] = erstes Argument usw. +int main (int argc, char** argv) { + // Ausgabe mit Hilfe von printf (print formatted) + // %d ist ein Integer. + // \n steht für eine neue Zeile + printf("%d\n",0); // => Gibt 0 aus. + + //////////////////////////////////////////////// + // Operatoren + //////////////////////////////////////////////// + + // Kurzschreibweise für mehrere Deklarationen + int i1 = 1, i2 = 2; + flaot f1 = 1.0, f2 = 2.0; + + int b,c; + b = c = 0; + + // Arithmetik ist unkompliziert + 1 + 2; // => 3 + 2 - 1; // => 1 + 2 * 1; // => 2 + 1 / 2; // 0 (0.5, aber abgeschnitten, da es int sind.) + + // Man muss mindestens ein Integer zu einen float konvertieren, damit man als + // Resultat eine Gleitkommazahl erhält. + (float)1 / 2; // => 0.5f + 1 / (double)2; // => 0.5 // das gleiche mit dem Typ `double` + 1.0 / 2.0; // => 0.5, plus oder minus Epsilon + // Gleitkommazahlen und deren Berechnungen sind nicht exakt. + + // Es gibt auch die Möglichkeit, Modulo zu rechnen + 11 % 3; // => 2 + + // Vergleichsoperatoren sind vielleicht schon bekannt, aber in C gibt es + // keinen Boolean-Typ. In C verwenden wir `int`. (Oder _Bool oder bool in C99) + // 0 ist falsch, alles andere ist wahr (Die Vergleichsoperatoren ergeben + // immer 1 oder 0. + 3 == 2; // => 0 (falsch) + 3 != 2; // => 1 (wahr) + 3 > 2; // => 1 + 3 < 2; // => 0 + 2 <= 2; // => 1 + 2 >= 2; // => 1 + + // C ist nicht Python - Vergleiche können nicht einfach verkettet werden. + // Warnung: die folgende Zeile wird kompilieren, aber es bedeutet `(0 < a) < 2`. + // Dieser Ausdruck ist immer wahr, weil (0 < a) kann entweder 1 oder 0 sein. + // In diesem Falle ist es 1, weil (0 < 1). + int zwischen_0_und_2 = 0 < a < 2; + // Benutze stattdessen folgende Schreibweise: + int zwischen_0_und_2 = 0 < a && a < 2; + + // Logik funktioniert auch mit ints + !3; // => 0 (logisches Nicht) + !0; // => 1 + 1 && 1; // => 1 (logisches Und) + 0 && 1; // => 0 + 0 || 1; // => 1 (logisches Oder) + 0 || 0; // => 0 + + // Bedingter ternärer Ausdruck ( ? : ) + int e = 5; + int f = 10; + int z; + z = ( e > f ) ? e : f; // => // => 10 "wenn e > f ist, gib e zurück, sonst f." + + // Inkrementierungs- und Dekrementierungsoperatoren + int j = 0; + int s = j++; // gib j zurück und erhöhe danach j. (s = 0, j = 1) + s = ++j; // erhöhe zuerst j und gib dann j zurück (s = 2, j = 2) + // das gleiche gilt für j-- und --j + + // Bitweise Operatoren + ~0x0F; // => 0xFFFFFFF0 (Bitweise Negation, "Einer-Komplement", + // Beispielresultat für 32-Bit int) + 0x0F & 0xF0; // => 0x00 (Bitweises UND) + 0x0F | 0xF0; // => 0xFF (Bitweises ODER) + 0x04 ^ 0x0F; // => 0x0B (Bitweises XOR) + 0x01 << 1; // => 0x02 (Bitweises Linksverschiebung (left shift) (um 1)) + 0x02 >> 1; // => 0x01 (Bitweises Rechtsverschiebung (right shift) (um 1)) + + // Sei vorsichtig beim Shift mit vorzeichenbehafteten Integern + // folgende Ausdrücke sind nicht definiert: + // - Verschiebung in das Vorzeichenbit (int a = 1 << 31) + // - Linksshift einer negativen Zahl (int a = -1 << 2) + // - Shift um einen Offset, welcher >= die Breite des linken Ausdrucks ist. + // int a = 1 << 32; // undefiniertes Verhalten, wenn int 32-Bit ist. + + + //////////////////////////////////////////////// + // Typen + //////////////////////////////////////////////// + + // Compiler, welche nicht C99-kompatibel sind, verlangen, dass sämtliche + // Variablen zu Beginn des Blocks deklariert werden. + // C99-Konforme Compiler erlauben die Variablendeklaration an dem Punkt, an + // welchem die Variable verwendet wird. + // Wir deklarieren die Variablen dynamisch im Code um die Lesbarkeit im + // Tutorial zu verbessern. + + // integer sind normalerweise 4 Bytes groß + int x_int = 0; + + // shorts sind normalerweise 2 Bytes groß + short x_short = 0; + + // chars sind garantiert 1 Byte groß + char x_char = 0; + char y_char = 'y'; // Charakterliterale werden mit '' gekennzeichnet. + + // longs sind oft 4 bis 8 Bytes groß. long long sind garantiert mindestens + // 8 Bytes groß. + long x_long = 0; + long long x_long_long = 0; + + // floats sind normalerweise 32-Bit Gleitkommazahlen + float x_float = 0.0f; // 'f'-Suffix beschreibt eine Gleitkommazahl. + + // doubles sind normalerweise 64-Bit Gleitkommazahlen + double x_double = 0.0; // echte Zahlen ohne Suffix sind vom Typ double + + // integer-Typen können vorzeichenlos (unsigned) sein + // (größer oder kleiner als 0) + unsigned short ux_short; + unsigned int ux_int; + unsigned long long ux_long_long; + + // Zeichen innerhalb von einfachen Anführungszeichen sind Integers im + // Maschinenzeichensatz + '0'; // => 48 im ASCII-Zeichensatz + 'A'; // => 65 im ASCII-Zeichensatz + + // sizeof(T) gibt die Größe einer Variablen des Typen T in Bytes zurück. + // sizeof(obj) ergibt die Größe des Ausdrucks (Variable, Literal usw.) + + printf("%zu\n", sizeof(int)); // => 4 (auf den Rechnern mit einem 4-Byte-Wort) + + // Wenn das Argument des `sizeof`-Operator ein Ausdruck ist, dann wird das + // Argument nicht ausgewertet (außer Arrays mit variabler Länge) + // Der Wert, der in diesem Fall zurückgegeben wird, ist eine Konstante zur + // Kompillierzeit. + + int a = 1; + //size_t ist ein vorzeichenloser Integer Typ mit mindestens 2 Byte um die + // Größe eines Objekts zu repräsentieren. + size_t size = sizeof(a++); // a++ wird nicht ausgewertet + printf("sizeof(a++) = %zu, wobei a=%d ist\n", size, a); + // Gibt "sizeof(a++) = 4, wobei a=1 ist" aus (mit einer 32-Bit-Architektur) + + // Arrays müssen mit einer Größe initialisiert werden. + char my_char_array[20]; // Dieses Array beinhaltet 1 * 20 = 20 Bytes + int my_int_array[20]; // Dieses Array beinhaltet 4 * 20 = 80 Bytes. + // unter der Voraussetzung eines 4-Byte-Worts. + + // Ein Array kann auf diese Weise mit 0 initialisiert werden. + char my_array[20] = {0}; + // Hierbei ist der Teil "{0}" der "Array Initialisierer". + // Beachte, dass die Länge des Arrays nicht explizit definiert werden muss, + // wenn er auf derselben Linie initialisiert wird. + // Folgende Deklaration ist gleichwertig: + char my_array[] = {0}; + // Allerdings muss die Länge des Arrays dann zur Laufzeit ausgewertet werden: + size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); + // WARNUNG: Wenn dieser Ansatz gewählt wird, muss man sicherstellen, dass die + // Größe des Arrays ermittelt werden *bevor* dieser einer Funktion als + // Argument weitergegeben wird (siehe Diskussion weiter unten), weil Arrays + // einer Funktion nur als Zeiger übergeben werden. => Das obere Statement + // würde innerhalb einer Funktion ein falsches Resultat liefern. + + // Das Indexieren eines Arrays funktioniert wie in anderen Sprache - resp. + // in anderen Sprachen funktioniert es gleich wie in C. + my_array[0]; // => 0 + + // Arrays sind veränderbar; es ist nur Arbeitsspeicher! + my_array[1] = 2; + printf("%d\n", my_array[1]); // => 2 + + // In C99 (und als optionales Feature in C11) können Arrays mit variabler + // Länge deklariert werden. Die Größe eines solchen Array muss eine Konstante + // zur Kompilierzeit sein. + printf("Geben Sie die Arraygröße an: "); //Frag den Benutzer nach + // der Arraygröße + int array_size; + fcsanf(stdin, "%d", &array_size); + int var_length_array[array_size]; // deklariere Array mit variabler Länge + printf("sizeof array =%zu\n", sizeof var_length_array); + + // Zum Beispiel: + // > Geben Sie die Arraygröße an: 10 + // > sizeof array = 40 + + // Strings sind lediglich Arrays von `chars`, welche mit einem Null-Byte + // (0x00) beendet werden. In Strings wird das Nullbyte durch das Zeichen \0 + // repräsentiert. Wir müssen das Null-Byte nicht angeben in String-Literalen; + // der Compiler fügt es am Ende des Array automatisch hinzu. + char a_string[20] = "Das ist ein String"; + printf("%s\n", a_string); // %s formattiert einen String + + printf("%d\n", a_string[18]); // => 0 + // Hier ist das Byte #19 0 (wie auch Byte #20) + + // Wenn wir Zeichen zwischen einfachen Anführungszeichen haben, ist es ein + // Zeichenliteral vom Typ int und *nicht* char. (aus historischen Gründen) + int cha = 'a'; // Ok + char chb = 'a'; // auch ok (implizite Umwandlung von int zu char) + + // Mehrdimensionale Arrays: + int multi_array[2][5] = { + {1,2,3,4,5}, + {6,7,8,9,0} + }; + // Auf Elemente zugreifen: + int array_int = multi_array[0][2]; // => 3 + + //////////////////////////////////////////////// + // Kontrollstrukturen + //////////////////////////////////////////////// + if (0) { + printf("Ich werde nie ausgeführt."); + } + else if (0) { + printf("Ich werde auch nie ausgeführt."); + } + else { + printf("Ich gebe etwas aus."); + } + + // While-Schleifen existieren auch + int ii = 0; + while (ii < 10) { // JEDER Wert unter zehn ist wahr + printf("%d, " ii++); //i++ inkrementiert ii NACHDEM der Wert gebraucht + // wurde. + } // => gibt folgendes aus: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + int kk = 0; + do { + printf("%d, ", kk); + } while(++kk < 10); //++kk inkrementiert kk BEVOR der Wert gebraucht wurde. + // => gibt folgendes aus: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + // In C gibt es auch for-Schleifen + int jj; + for (jj = 0; jj < 10; jj++) { + printf("%d, ", jj); + } // => gibt folgendes aus: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + // **Merke** + // Schleifen und Funktionen müssen einen Rumpf haben. Wenn kein Rumpf gebraucht + // wird, kann folgendes gemacht werden: + int i; + for (i = 0; i <= 5; i++) { + ; // Semikolon wird als Rumpf behandelt (Null-Anweisung) + } + // Alternativ kann auch folgendes geschrieben werden: + for (i = 0; i <= 5; i++); + + // Verzweigungen mit mehreren Möglichkeiten: `switch()` + switch (a) { + case 0: // Labels müssen integrale *konstante* Ausdrücke sein (z.B. Enums) + printf("Hey, 'a' ist gleich 0!\n"); + break; //Wenn du kein break einsetzt, so geht der Kontrollfluss + // durch die Labels + case 1: + printf("Huh, 'a' ist gleich 1!\n"); + break; + // Sei vorsichtig - wenn man das `break` vergisst, werden alle + // Anweisungen ausgeführt bis das nächste `break` erscheint. + case 3: + case 4: + printf("Schau mal ... 'a' ist entweder 3 oder 4.\n"); + break; + default: + // wenn der Ausdruck `a` auf kein Label zutrifft. + fputs("Fehler!\n", stderr); + exit(-1); + break; + } + + //////////////////////////////////////////////// + // Typenumwandlung + //////////////////////////////////////////////// + + // Jeder Wert in C hat einen bestimmten Typen, aber es ist möglich, ein + // Wert in einen anderen Typ umzuwandeln (mit einigen Einschränkungen). + + int x_hex = 0x01; // Es ist möglich, Variablen Hexadezimalwerten zuzuweisen. + + // Bei der Umwandlung zwischen Typen wird versucht, den numerischen Wert + // beizubehalten. + printf("%d\n", x_hex); // => 1 + printf("%d\n", (short) x_hex); // => 1 + printf("%d\n", (char) x_hex); // => 1 + + // Typen werden überlaufen (overflow) ohne jegliche Warnung + printf("%d\n", (unsigned char) 257); // => 1 (Max char=255 wenn char 8 Bit ist) + + // Um den maximalen Wert eines `char`, `signed char` oder `unsigned char` + // herauszufinden, können die Makros `CHAR_MAX`, `SCHAR_MAX` und `UCHAR_MAX` + // aus der Header-Datei `<limits.h>` verwendet werden. + + // Integer-Typen können zu Gleitkommazahlen und umgekehrt umgewandelt werden. + printf("%f\n", (double) 100); // %f formattiert immer zu einem `double`... + printf("%f\n", (flaot) 100); // ... auch mit einem `float` + printf("%d\n", (char)100.0); + + //////////////////////////////////////////////// + // Zeiger (aka Pointer) + //////////////////////////////////////////////// + + // In diesem Tutorial wird das deutsche Wort Zeiger nicht verwendet, da es + // bei einer weiteren Recherche einfacher ist, wenn man von Pointern ausgeht. + // Außerdem ist der Begriff Pointer auch im deutschen Sprachgebrauch zu finden. + + // Ein Pointer ist eine Variable, welche deklariert wurde, um eine Speicher- + // adresse zu speichern. Die Deklaration eines Pointers wird auch zeigen, + // auf welche Art von Daten der Pointer zeigt. Man kann die Speicheradresse + // von Variablen abrufen und dann mit diesen herumspielen. + + int x = 0; + printf("%p\n", (void *)&x); // verwende & um die Adresse der Variable + // zu erhalten + // %p formattiert einen Objektpointer des Typen void*) + // => Gibt eine Adresse im Speicher aus + + // Pointer starten mit einem * zu Beginn der Deklaration. + int *px, not_a_pointer; // px ist ein Pointer zu einem int. + px = &x; // Speichert die Adresse von x in px + printf("%p\n", (void *)px); // => Gibt eine Adresse im Speicher aus + printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); + // Gibt auf einem typischen 64-Bit-System folgendes aus: "8, 4" + + // Um den Wert einer Adresse, auf welche ein Pointer zeigt, herauszufinden, + // muss man vor die Variable ein * setzen, um sie zu dereferenzieren. + // Notiz: Ja, es kann verwirrend sein, dass '*' sowohl für das Deklarieren + // als auch das Derefenzieren verwendet werden kann. + printf("%d\n", *px); // => 0, der Wert von x + + // Man kann den Wert, auf welchen ein Pointer zeigt, auch verändern. + // Man muss die Dereferenzierung in Klammern setzen, weil ++ eine höhere + // Priorität als * hat. + (*px)++; // Inkrementiere den Wert, auf welchen px zeigt, um 1 + printf("%d\n", *px); // => 1 + printf("%d\n", x); // => 1 + + // Arrays sind eine gute Möglichekit, einen zusammenhängenden Block von + // Speicher zu allozieren. + int x_array[20]; // deklariert einen Array der Größe 20 (Größe kann + // nicht geändert werden.) + int xx; + for (xx =0; xx < 20; xx++) { + x_array[xx] 20 -xx; + } // Initialisiere x_array zu 20, 19, 18, ... 2, 1 + + // Deklariere ein Pointer des Typs int und initalisiere ihn, um auf `x_array` + // zu zeigen. + int *x_ptr = x_array; + // x_ptr zeigt jetzt auf den ersten Wert innerhalb des Arrays (int 20) + // Das funktioniert, weil Arrays oft zu Pointern reduziert werden, welche + // auf das erste Element zeigen. + // Zum Beispiel: Wenn ein Array einer Funktion mitgegeben wird oder einem + // Pointer zugewiesen wird, wird es zu einem Pointer reduziert (implizites Casting) + // Ausnahme: Wenn das Array das Argument des Operators `&` ist. + int arr[10]; + int (*ptr_to_arr)[10] = &arr; //`&arr` ist nicht vom Typ `int *`! + // Es ist vom Typem "Pointer auf Array" (aus zehn `int`s) + // oder wenn das Array ein Stringliteral ist, welches gebraucht wird um ein + // `char`-Array zu initialisieren. + char other_arr[] = "foobarbazquirk"; + // oder wenn es das Argument des `sizeof` oder `alignof` Operators ist. + int third_array[10]; + int *ptr = third_array; // gleich wie: `int *ptr = &arr[0]` + printf("%zu, %zu\n", sizeof(third_array), sizeof(ptr)); + // Gibt wahrscheinlich "40, 4" oder "40, 8" aus + + // Pointer werden basierend auf dem Typ in- und dekrementiert + // Dies wird Pointer-Arithmetik genannt. + printf("%d\n", *(x_ptr + 1)); // => 19 + printf("%d\n", x_array[1]); // => 19 + + // Man kann zusammenhängende Speicherblöcke auch mit der Funktion `malloc` + // aus der Standardbibliothek dynamisch allozieren. Der Funktion `malloc` + // muss ein Argument des Typs `size_t` übergeben werden, welches bestimmt, + // wie viele Bytes alloziert werden sollen. (Normalerweise geschieht dies + // aus dem Heap - dies kann auf eingebetteten Systemen unterschiedlichen sein. + // Der C Standard sagt nichts darüber.) + int *my_ptr = malloc(sizeof(*my_ptr) * 20); + for (xx = 0; xx < 20; xx++) { + *(my_ptr + xx) = 20 -xx; //my_ptr[xx] = 20-xx + } // initialisiere Speicher zu 20, 19, 18, 17, ... 2, 1 (als `int`) + + // Sei vorsichtig beim Übergeben von Benutzerdefinierten Werten an `malloc`. + // Wenn du sicher sein willst, kannst du die Funktion `calloc` nutzen, welche + // (nicht wie `malloc`) auch den Speicher nullt. + int *my_other_ptr = calloc(20, sizeof(int)); + + // Merke, dass es in C keinen Standard-Weg gibt, um die Länge eines dynamisch + // allozierten Arrays zu bestimmen. Auf Grund dessen sollte eine Variable + // erstellt werden, welche sich die Anzahl der Elemente im Array merkt, wenn + // die Arrays mehrmals im Programm gebraucht werden. + // Weitere Informationen stehen im Abschnitt Funktionen. + size_t size = 10; + int *my_array = calloc(size, sizeof(int)); + // Füge dem Array ein Element hinzu + size++; + my_array = realloc(my_array, sizeof(int) *size); + if (my_array == NULL) { + // Denke daran, realloc-Fehler zu prüfen + return + } + my_array[10] = 5; + + // Das Dereferenzieren von nicht alloziertem Speicher führt zu einem + // Undefinierten Verhalten. + printf("%d\n", *(my_ptr + 21)); // Gibt irgendwas aus. + // Das Programm kann auch abstürzen + + // Nachdem du fertig mit einem Block bist, welcher `malloc` verwendet hat, + // muss der Speicher befreit werden. Ansonsten kann dieser Speicherbereich + // niemand nutzen bis dein Programm beendet wird. + // Dies wird auch als "Speicherleck" (engl: memory leak) bezeichnet. + free(my_ptr); + + // Obwohl Strings normalerweise als Pointer-to-Char (Pointer zum ersten + // Zeichen des Arrays) repräsentiert werden, sind Strings Arrays aus `char`s. + // Es ist eine gute Praxis, `const char *` zu verwenden, wenn man ein + // String-Literal referenziert, da String-Literale nicht modifiziert werden + // sollten (z.B. "foo"[0] = 'a' ist ILLEGAL) + const char *my_str = "Das ist mein eigener String"; + printf("%c\n", *my_str); // => D + + // Dies ist nicht der Fall, wenn der String ein Array (möglicherweise mit + // einem String-Literal initialisiert) ist, welcher im beschreibbaren Speicher + // bleibt, wie zum Beispiel in: + char foo[] = "foo"; + foo[0] = 'a'; // Dies ist legal, foo enthält jetzt "aoo" + + function_1(); +} // Ende der `main`-Funktion + +//////////////////////////////////////////////// +// Funktionen +//////////////////////////////////////////////// + +// Syntax einer Funktionsdeklaration +// <rueckgabe_wert> <funktions_name>(<args>) + +int add_two_ints(int x1, int x2) { + return x1 + x2; // verwendet return, um einen Wert zurückzugeben +} + +/* +Funktionen werden auf Grund des Wertes aufgerufen (call-by-value). Wenn eine +Funktion aufgerufen wird, sind die Argumente Kopien der ursprünglichen Werte +(ausgenommen Arrays). Alles, was man innerhalb einer Funktion mit den Werten +macht, hat keinen Einfluss auf die Originalwerte als die Funktion aufgerufen +wurde. + +Verwende Pointer, um den Originalinhalt zu bearbeiten. + +Beispiel: +*/ + +// Eine `void`-Funktion gibt keinen Wert zurück +void str_reverse(char *str_in) { + char tmp; + size_t ii = 0; + size_t size = strlen(str_in); + // `strlen()` ist ein Teil der C Standard-Bibliothek. + // Merke: Die Länge, welche von `strlen` zurückgegeben wird, ist ohne den + // Null-Byte Terminator. + for (ii = 0; i < size /2; ii++) { // in C99 kann man `ii` hier deklarieren. + tmp = str_in[ii]; + str_in[ii] = str_in[size - ii - 1]; //#ii'tes Zeichen vom Ende her + str_in[size - ii- 1] = tmp; + } +} +// Merke: Die `string.h`-Headerdatei muss inkludiert werden, bevor `strlen()` +// verwendet werden kann. + +/* +char c[] = "Das ist ein Test"; +str_reverse(c); +printf("%s\n", c), => "tseT nie tsi saD" +*/ + +// Weil wir lediglich eine Variable zurückgeben können, kann zum Ändern mehrerer +// Variablen das Konzept call-by-reference verwendet werden. +void swap_two_numbers(int *a, int *b) { + int temp = *a; + *a = *b; + *b = temp; +} +int first = 10; +int seconde = 20; +printf("Erste Zahl: %d\n Zweite Zahl: %d\n", first, second); +swap_two_numbers(&first, &second); +printf("Erste Zahl: %d\n Zweite Zahl: %d\n", first, second); +// Werte sind vertauscht. + +/* +Wenn man Arrays betrachtet, so werden diese immer als Pointer übergeben. Auch +wenn die Arrays statisch alloziert werden (wie zum Beispiel `arr[10]`), werden +diese als Pointer zum ersten Element des Arrays übergeben. +Auch hier soll noch einmal erwähnt werden, dass es keinen Standard gibt, wie die +Größe eines dynamischen Arrays herausgefunden werden kann. +*/ +// Die Größe des Arrays muss unbedingt mitgegeben werden. +// Sonst hat die Funktion keine Ahnung wie groß das Array ist. +void print_int_arrray(int *arr, size_t size) { + int i; + for (i = 0; i < size; i++) { + printf("arr[%d] ist %d\n", i, arr[i]); + } +} + +int my_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +int size = 10; +print_int_array(my_array, size); +// Wird folgendes ausgeben: "arr[0] ist 1" usw. + +// Wenn man auf externe Variable (außerhalb der Funktion) referenziert, sollte +// man das Schlüsselwort `extern` verwenden. +int i = 0; +void test_function() { + extern int i; // i braucht nun die externe Variable i +} + +// Das Schlüsselwort `static` macht, dass eine Variable außerhalb der Kompilier- +// einheit nicht zugreifbar ist. (Auf den meisten Systemen ist eine Kompiliereinheit +// eine `.c`-Datei.) Das Schlüsselwort `static` kann sowohl bei globalen +// (zur Kompiliereinheit gehörende) Variablen, Funktionen und Funktionslokale +// Variablen angewendet werden. +// Wenn man `static` bei lokalen Variablen verwendet, so ist diese Variable global +// erreichbar und behält dessen Wert über Funktionsaufrufe hinweg, aber sie ist +// nur innerhalb der deklarierten Funktion verfügbar. Außerdem werden statische +// Variablen mit 0 initialisiert, wenn sie nicht mit einem anderen Startwert +// initialisiert werden. +// Es ist auch möglich, Funktionen als statisch zu deklarieren, damit diese +// `private` sind. Privat heißt, dass sie nur in diesem Kontekt sichtbar sind. + + +//////////////////////////////////////////////// +// Benutzerdefinierte Typen und Strukturen (Structs) +//////////////////////////////////////////////// + +// `typedef`s können verwendet werden, um Typenaliase zu erstellen. +typedef int my_type; +my_type my_type_var = 0; + +// Structs sind lediglich Sammlungen von Daten, die Inhalte werden +// (in der Reihenfolge wie sie geschrieben wurden) sequentiell alloziert. +struct rectangle { + int width; + int height; +}; + +// Allgemein ist es nicht so, dass folgender Ausdruck wahr ist. +// sizeof(struct rectangle) == sizeof(int) + sizeof(int) +// Dies ist so, weil potentiell ein Padding zwischen den Struktur-Inhalten +// möglich ist). (siehe [1, Englisch]) + +void function_1() { + struct rectangle my_rectangle; + + // Greife auf Struct-Inhalte mit `.` zu. + my_rectangle.width = 10; + my_rectangle.height = 20; + + // Du kannst Pointer zu Structs deklarieren. + struct rectangle *my_rectangle_ptr = &my_rectangle; + + // Verwende Dereferenzierung, um Struct-Inhalte zu bearbeiten + (*my_rectangle_ptr).width = 30; + + //Noch besser: Verwende die Kurzschreibweise ->, um die Lesbarkeit zu + // verbessern. + my_rectangle_ptr->height = 10; // Gleich wie: (*my_rectangle_ptr).height = 10; +} + +// Aus Bequemlichkeitsgründen ist es möglich einem `struct` ein `typedef` hinzuzufügen. +typedef struct rectangle rect; + +int area(rect r) { + return r.width * r.height; +} + +// Wenn du große Structs hast, kannst du diese mit dem Pointer kopieren, +// damit große Kopiervorgänge vermieden werden. +int area_ptr(const rect *r) { + return r->width * r->height; +} + +//////////////////////////////////////////////// +// Funktionspointer +//////////////////////////////////////////////// + +/* +Zur Laufzeit sind Funktionen in einer Speicheradresse gespeichert. +Funktionspointer sind wie normale Pointer (es wird einfach eine Speicheradresse +gespeichert). Funktionspointer können verwendet werden, um Funktionen und +Handler (oder Callback-Funktionen) direkt aufzurufen. +Wie auch immer, die Syntax kann zu Beginn verwirrend wirken. + +Zum Beispiel: Verwende str_reverse von einem Pointer +*/ +void str_reverse_through_pointer(char *str_in) { + // Definiere eine Funktionspointer-Variable, welche f genannt wird. + void (*f)(char *); // Signatur sollte genau der Funktion entsprechen. + f = &str_reverse; // weise die Adresse der wirklichen Funktion zu + // (zur Laufzeit bestimmt) + // `f = str_reverse;` würde auch funktionieren, da Funktionen zu Pointern + // reduziert werden (ähnlich wie Arrays) + (*f)(str_in); // Die Funktion einfach mit dem Pointer aufrufen + // f(str_in); // Dies ist eine weitere gültige Alternative um eine Funktion + // auzurufen. +} + +/* +Solange die Signaturen der Funktionen übereinstimmen, kann man sämtliche Funktionen +demselben Pointer zuweisen. Funktionspointer sind auf Grund der Einfacheit und +Leserlichkeit normalerweise wie folgt `typedef`d +*/ +typedef void (*my_fnp_type)(char *); +// Danach werden diese genutzt, um die wirkliche Pointervariable zu deklarieren. +// .. +// my_fnp_type f; + +// Spezialzeichen +// Im folgenden sin die englischen Begriffe jeweils in Klammern geschrieben, +// da diese Begriffe auch im deutschten Sprachgebrauch verwendet werden. +'\a'; // Alarmzeichen (alert (bell) character) +'\n'; // Zeichen für neue Linie (newline character) +'\t'; // Tab (tab character (left justifies text)) +'\v'; // Vertikaler Tab (vertical tab) +'\f'; // Neue Seite (new page (form feed)) +'\r'; // Wagenrücklauf (carriage return) +'\b'; // Backspace-Zeichen (backspace character) +'\0'; // Null-Byte (NULL character). In C wird dieses Zeichen normalerweise am +// Ende eines Strings gesetzt. +// Beispiel: Hallo\n\0. "\0" wird per Konvention verwendet, um das Ende +// eines Strings zu kennzeichnen. +'\\'; // Backslash (backslash) +'\?'; // Fragezeichen (question mark) +'\''; // einfaches Anführungszeichen (single quote) +'\"'; // doppeltes Anführungszeichen (double quote) +'\xhh'; // Hexadezimale Zahl (hexadecimal number.) Beispiel: + // '\xb' = Zeichen für vertikalen Tab +'\0oo'; // Oktalzahl (octal number). Beispiel \013 = Zeichen für vertikalen Tab + +//Ausgabeformatierung +"%d"; // Integer +"%3d"; // Integer mit einer minimalen Länge von drei Zeichen. +"%s"; // String +"%f"; // Gleitkommazahl (float) +"%ld"; // genauere Gleitkommazahl (long) +"%3.2f"; // Mindestens drei Zeichen vor und drei nach dem Komma. +"%7.4s"; // (Kann auch mit Strings gemacht werden) +"%c"; // einzelnes Zeichen (char) +"%p"; // Pointer. Merke: man muss den Pointer zu void umwandeln, + // bevor `printf` funktioniert. +"%x"; // Hexadezimal +"%o"; // Oktalzahl +"%%"; // Gibt % aus + +//////////////////////////////////////////////// +// Reihenfolge der Auswertung von Operatoren +//////////////////////////////////////////////// + +//-------------------------------------------------------// +// Operatoren | Assoziativität // +//-------------------------------------------------------// +// () [] -> . | linksassoziativ // +// ! ~ ++ -- + = *(type)sizeof | rechtsassoziativ // +// * / % | linksassoziativ // +// + - | linksassoziativ // +// << >> | linksassoziativ // +// < <= > >= | linksassoziativ // +// == != | linksassoziativ // +// & | linksassoziativ // +// ^ | linksassoziativ // +// | | linksassoziativ // +// && | linksassoziativ // +// || | linksassoziativ // +// ?: | rechtsassoziativ // +// = += -= *= /= %= &= ^= |= <<= >>= | rechtsassoziativ // +// , | linksassoziativ // +//-------------------------------------------------------// + + +//////////////////////////////////////////////// +// Header-Dateien +//////////////////////////////////////////////// + +/* +Header-Dateien sind ein wichtiger Teil von C, da sie eine Verbindung zwischen +unterschiedlichen C-Quelldateien herstellen. Außerdem vereinfachen Header-Dateien +den Code und Definitionen, da diese in separaten Dateien geschrieben werden können. + +Header-Dateien sind von der Syntax her ähnlich zu C-Quelldateien, allerdings haben +die Header-Dateien die Dateiendung `.h`. Header-Dateien können im Quellcode mit +der `#include`-Anweisung eingebunden werden z.B. `#include "beispiel.h". Die +vorherige Anweisung geht davon aus, dass sich die Header-Datei im selben Ordner +befindet wie die C-Quelldatei. +*/ + +// Eine sichere Möglichkeit, einen Header mehrere Male zu definieren bietet, das +// folgende Statement. Die mehrfache Definition geschieht, wenn Kreisabhängigkeiten +// bestehen. +#ifndef EXAMPLE_H /* Wenn EXAMPLE_H noch nicht definiert wurde */ +#define EXAMPLE_H /* definiere das Makro EXAMPLE_H */ + +// Es könenn weitere Header innerhalb eines Headers eingebunden werden, was dazu +// führt, dass diese bereits in anderen Dateien eingebunden wurden. So kann eine +// Header-Datei in mehreren Dateien eingebunden werden. zum Beispiel: +#include <string.h> + +// Wie in den Quelldateien können auch in den Header-Dateien Makros definiert +// werden und in anderen Dateien verwendet werden, welche diesen Header einbinden. +#define EXAMPLE_NAME "Dennis Ritchie" + +// Funktionsmakros können auch definiert werden. +#define ADD(a, b) ((a) + (b)) + +// Beachte die Klammern, welche um die Argumente geschrieben wurden - diese sind +// wichtig, damit sichergestellt werden kann, dass a und b nicht unerwartet +// erweitert werden. Zum Beispiel: `MUL (x,y) (x * y)`; Bei der Verwendung von +// `MUL(1 + 2, 3)` würde dies wie folgt erweitert werden: `(1 + 2 * 3)`, was zu +// einem falschen Resultat führt. + +// Strukturen und Typendefinitionen können verwendet werden, um die Konsistenz +// zwischen unterschiedlichen Dateien beizubehalten. +typedef struct Node { + int value; + struct Node *next; +}Node; + +// Dies kann auch mit Aufzählungen gemacht werden. +enum traffic_light_state {GREEN, YELLOW, RED}; + +// Funktionsprototypen könenn auch in Header-Dateien definiert werden, um die +// Funktion in unterschiedlichen Dateien zu verwenden, aber dies wird als schlechte +// Praxis angesehen. Definitionen sollten in einer C-Datei erstellt werden. +Node create_linked_list(int *value, int length); + +// Außer den oben genannten Elementen, sollten weitere Definitionen in einer +// C-Datei gemacht werden. Übermäßige Includes und Definitionen sollten auch +// nicht einer Header-Datei gemacht werden. Stattdessen wird es empfohlen, diese +// in eine separate Header-Datei oder in eine C-Quelldatei zu schreiben. + +#endif /* Ende der Präprozessordirektive */ +``` +## Weiterführende Literatur + +Das Beste wird es sein, wenn man sich ein Exemplar des Buches +["The C Programming Language"](https://de.wikipedia.org/wiki/The_C_Programming_Language) besorgt. +Dieses Buch gilt als **das** Buch über die Programmiersprache C und wurde +von Dennis Ritchie, dem Erfinder der Programmiersprache C, und Brian Kernighan +geschrieben. +Sei vorsichtig, da dieses Buch mittlerweile schon etwas älter ist und gewisse +Unkorrektheiten (d.h. Ideen, welche nicht mehr als gut empfunden werden.) oder +mittlerweile geänderte Praktiken enthält. [Hinweis: Das Buch wurde auf Englisch +geschrieben, es gibt aber auch eine Übersetzung davon] + +Eine weitere gute Ressource ist [Learn C The Hard Way](http://learncodethehardway.org/c/). +[Englisch] + +Solltest du Fragen zu C haben, so lies die FAQ [compl.lang.c Frequently Asked Questions](http://c-faq.com).[Englisch] + +Außerdem ist es wichtig, eine saubere Einrückung zu verwenden. Des weiteren ist +es wichtig, dass der Codestil möglichst konsistent ist. Es ist wichtiger, lesbaren +Code zu schreiben als Code, welcher clever und schnell ist. Es lohnt sich ein +Blick auf den [Codestil des Linuxkernel](https://www.kernel.org/doc/Documentation/process/coding-style.rst) zu werfen. [Englisch] + +[1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) diff --git a/de-de/css-de.html.markdown b/de-de/css-de.html.markdown index c31e73d2..da706e91 100644 --- a/de-de/css-de.html.markdown +++ b/de-de/css-de.html.markdown @@ -27,7 +27,7 @@ In diesem Artikel wird am meisten auf generelle Hinweise und die Syntax geachtet ####################*/ /* Eigentlich ist das grundlegende CSS-Statement sehr simpel */ -selektor { eigenschaft: wert; /* mehr eigenschaften...*/ } +selektor { eigenschaft: wert; /* mehr Eigenschaften...*/ } /* Der Selektor wird dazu benutzt, ein Element auf der Seite auszuwählen. @@ -35,7 +35,7 @@ Man kann aber auch alle Elemente auf einer Seite auswählen! */ * { color:red; } /* farbe:rot */ /* -Angenommen wir haben folgendes Element auf einer Seite: +Angenommen, wir haben folgendes Element auf einer Seite: <div class='eine-klasse klasse2' id='eineId' attr='wert' /> */ @@ -170,7 +170,7 @@ empfohlen ist --> ## Spezifität Ein Element kann natürlich auch von mehr als einer Regel in einem Stylesheet -angesprochen werdenm und kann eine Eigenschaft auch öfters als einmal zugewiesen +angesprochen werden und kann eine Eigenschaft auch öfters als einmal zugewiesen bekommen. In diesen Fällen gibt es Regeln, die die Spezifität von Selektoren regeln. Wir haben dieses CSS: diff --git a/de-de/d-de.html.markdown b/de-de/d-de.html.markdown index 2b0b38dd..28ecc7ae 100644 --- a/de-de/d-de.html.markdown +++ b/de-de/d-de.html.markdown @@ -9,7 +9,7 @@ lang: de-de --- ```c -// Es war klar dass das kommt... +// Es war klar, dass das kommt... module hello; import std.stdio; @@ -20,13 +20,13 @@ void main(string[] args) { } ``` -Wenn du so wie ich bist und viel zeit im Internet verbringst stehen die Chancen gut -das du schonmal über [D](http://dlang.org/) gehört hast. -Die D-Sprache ist eine moderne, überall einsetzbare programmiersprache die von Low bis -High Level verwendet werden kann und dabei viele Stile anbietet. +Wenn du so wie ich bist und viel Zeit im Internet verbringst, stehen die Chancen +gut, dass du schonmal über [D](http://dlang.org/) gehört hast. +Die D-Sprache ist eine moderne, überall einsetzbare programmiersprache die von +Low bis High Level verwendet werden kann und dabei viele Stile anbietet. D wird aktiv von Walter Bright und Andrei Alexandrescu entwickelt, zwei super schlaue, -richtig coole leute. Da das jetzt alles aus dem weg ist - auf zu den Beispielen! +richtig coole leute. Da das jetzt alles aus dem Weg ist - auf zu den Beispielen! ```c import std.stdio; @@ -38,7 +38,7 @@ void main() { writeln(i); } - auto n = 1; // auto um den typ vom Compiler bestimmen zu lassen + auto n = 1; // auto um den Typ vom Compiler bestimmen zu lassen // Zahlenliterale können _ verwenden für lesbarkeit while(n < 10_000) { @@ -68,21 +68,22 @@ void main() { } ``` -Neue Typen können mit `struct`, `class`, `union`, und `enum` definiert werden. Structs und unions -werden as-value (koppiert) an methoden übergeben wogegen Klassen als Referenz übergeben werden. -Templates können verwendet werden um alle typen zu parameterisieren. +Neue Typen können mit `struct`, `class`, `union`, und `enum` definiert werden. +Structs und unions werden as-value (koppiert) an Methoden übergeben wogegen +Klassen als Referenz übergeben werden. Templates können verwendet werden um +alle Typen zu parameterisieren. ```c // Hier, T ist ein Type-Parameter, Er funktioniert wie Generics in C#/Java/C++ struct LinkedList(T) { T data = null; - LinkedList!(T)* next; // Das ! wird verwendet um T zu übergeben. (<T> in C#/Java/C++) + LinkedList!(T)* next; // Das ! wird verwendet, um T zu übergeben. (<T> in C#/Java/C++) } class BinTree(T) { T data = null; - // Wenn es nur einen T parameter gibt können die Klammern um ihn weggelassen werden + // Wenn es nur einen T Parameter gibt, können die Klammern um ihn weggelassen werden BinTree!T left; BinTree!T right; } @@ -97,7 +98,7 @@ enum Day { Saturday, } -// Aliase können verwendet werden um die Entwicklung zu erleichtern +// Aliase können verwendet werden, um die Entwicklung zu erleichtern alias IntList = LinkedList!int; alias NumTree = BinTree!double; @@ -111,8 +112,8 @@ T max(T)(T a, T b) { return a; } -// Steht ref vor einem Parameter wird sichergestellt das er als Referenz übergeben wird. -// Selbst bei werten wird es immer eine Referenz sein. +// Steht ref vor einem Parameter, wird sichergestellt, dass er als Referenz +übergeben wird. Selbst bei Werten wird es immer eine Referenz sein. void swap(T)(ref T a, ref T b) { auto temp = a; @@ -120,18 +121,18 @@ void swap(T)(ref T a, ref T b) { b = temp; } -// Templates können ebenso werte parameterisieren. +// Templates können ebenso Werte parameterisieren. class Matrix(uint m, uint n, T = int) { T[m] rows; T[n] columns; } -auto mat = new Matrix!(3, 3); // Standardmäßig ist T vom typ Integer +auto mat = new Matrix!(3, 3); // Standardmäßig ist T vom Typ Integer ``` Wo wir schon bei Klassen sind - Wie wäre es mit Properties! Eine Property -ist eine Funktion die wie ein Wert agiert. Das gibt uns viel klarere Syntax +ist eine Funktion, die wie ein Wert agiert. Das gibt uns viel klarere Syntax im Stil von `structure.x = 7` was gleichgültig wäre zu `structure.setX(7)` ```c @@ -187,18 +188,17 @@ void main() { ``` Mit properties können wir sehr viel logik hinter unseren gettern -und settern hinter einer schönen syntax verstecken +und settern hinter einer schönen Syntax verstecken -Other object-oriented goodies at our disposal Andere Objektorientierte features sind beispielsweise `interface`s, `abstract class` und `override`. Vererbung funktioniert in D wie in Java: -Erben von einer Klasse, so viele interfaces wie man will. +Erben von einer Klasse, so viele Interfaces wie man will. -Jetzt haben wir Objektorientierung in D gesehen aber schauen +Jetzt haben wir Objektorientierung in D gesehen, aber schauen wir uns noch was anderes an. -D bietet funktionale programmierung mit _first-class functions_ -puren funktionen und unveränderbare daten. +D bietet funktionale Programmierung mit _first-class functions_ +puren Funktionen und unveränderbaren Daten. Zusätzlich können viele funktionale Algorithmen wie z.B map, filter, reduce und friends im `std.algorithm` Modul gefunden werden! @@ -207,11 +207,11 @@ import std.algorithm : map, filter, reduce; import std.range : iota; // builds an end-exclusive range void main() { - // Wir wollen die summe aller quadratzahlen zwischen + // Wir wollen die Summe aller Quadratzahlen zwischen // 1 und 100 ausgeben. Nichts leichter als das! - // Einfach eine lambda funktion als template parameter übergeben - // Es ist genau so gut möglich eine normale funktion hier zu übergeben + // Einfach eine Lambda-Funktion als Template Parameter übergeben + // Es ist genau so gut möglich eine normale Funktion hier zu übergeben // Lambdas bieten sich hier aber an. auto num = iota(1, 101).filter!(x => x % 2 == 0) .map!(y => y ^^ 2) @@ -221,13 +221,13 @@ void main() { } ``` -Ist dir aufgefallen wie wir eine Haskell-Style pipeline gebaut haben +Ist dir aufgefallen, wie wir eine Haskell-Style Pipeline gebaut haben um num zu berechnen? Das war möglich durch die Uniform Function Call Syntax. -Mit UFCS können wir auswählen ob wir eine Funktion als Methode oder +Mit UFCS können wir auswählen, ob wir eine Funktion als Methode oder als freie Funktion aufrufen. Walters artikel dazu findet ihr [hier.](http://www.drdobbs.com/cpp/uniform-function-call-syntax/232700394) -Kurzgesagt kann man Funktionen deren erster parameter vom typ A ist, als +Kurzgesagt kann man Funktionen, deren erster Parameter vom typ A ist, als Methode auf A anwenden. Parrallel Computing ist eine Tolle sache, findest du nicht auch? @@ -239,10 +239,10 @@ import std.math : sqrt; void main() { // Wir wollen die Wurzel von jeder Zahl in unserem Array berechnen - // und dabei alle Kerne verwenden die wir zur verfügung haben + // und dabei alle Kerne verwenden, die wir zur verfügung haben auto arr = new double[1_000_000]; - // Wir verwenden den index und das element als referenz + // Wir verwenden den Index und das Element als Referenz // und rufen einfach parallel auf! foreach(i, ref elem; parallel(arr)) { ref = sqrt(i + 1.0); diff --git a/de-de/dhall-de.html.markdown b/de-de/dhall-de.html.markdown new file mode 100644 index 00000000..385c88be --- /dev/null +++ b/de-de/dhall-de.html.markdown @@ -0,0 +1,380 @@ +--- +language: Dhall +contributors: + - ["Gabriel Gonzalez", "http://www.haskellforall.com/"] +translators: + - ["Profpatsch", "http://profpatsch.de"] +filename: learndhall-de.py +lang: de-de +--- + +Dhall ist eine programmierbare Konfigurationssprache und bietet eine +nicht-repetetive Alternative zu YAML. + +Man kann Dhall sehen als: JSON + Funktionen + Typen + Importsystem + +Obwohl Dhall programmierbar ist, ist die Sprache nicht +turingvollständig. Viele von Dhalls Features benutzen diese +Einschränkung, um stärkere Sicherheitsgarantien zu bieten und besseres +Tooling zu ermöglichen. + +```haskell +-- einzeiliger Kommentar + +{- mehrzeiliger Kommentar + + Unicode funktioniert 🙂 + + Diese Datei ist eine valide Dhall-Expression und evaluiert zu einem + großen Record, welcher die Ergebnisse jedes Schritts beinhaltet. + + Das Ergebnis kann angezeigt werden, indem man die Datei evaluiert: + + $ dhall --file learndhall.dhall + + {- Kommentare können verschachtelt sein -} +-} + +let greeting = "Hallo, Welt!" + +let fruits = "🍋🍓🍍🍉🍌" + +let interpolation = "Ein paar leckere Früchte: ${fruits}" + +let multilineText {- Inline-Kommentare funktionieren ebenfalls -} = + '' + In Multiline-Text-Literals wird Whitespace am Anfang der Zeile + entfernt. + + Das bedeutet Text kann frei eingerückt oder ausgerückt werden, + ohne dass sich der Inhalt des Strings ändert. + + Relative Einrückungen bleiben erhalten. + + Ansonsten wird das Text-Literal verbatim erhalten, ähnlich + zu “literal”-Multiline-Strings in YAML. + '' + +let bool = True + +-- Typannotationen für Bindings sind optional, aber hilfreich, also +-- benutzen wir sie hier. +let annotation : Bool = True + +let renderedBool : Text = if bool then "True" else "False" + +-- Natürliche Zahlen sind nicht-negativ und vorzeichenlos. +let naturalNumber : Natural = 42 + +-- Integer können negativ sein, brauchen aber ein explizites Vorzeichen. +let positiveInteger : Integer = +1 + +let negativeInteger : Integer = -12 + +let pi : Double = 3.14159265359 + +{- Identifier dürfen eine große Anzahl an verschiedenen Zeichen + beinhalten (wie z.B. Anführungszeichen oder Whitespace), wenn man + sie mit Backticks umschließt. +-} +let `Avogadro's Number` : Double = 6.0221409e+23 + +let origin : { x : Double, y : Double } = { x = 0.0, y = 0.0 } + +let somePrimes : List Natural = [ 2, 3, 5, 7, 11 ] + +{- Ein Schema ist das gleiche wie ein Typ. + + Typnamen beginnen konventionell mit einem Großbuchstaben, was + jedoch nicht erzwungen wird. +-} +let Profile : Type + = { person : + { name : Text + , age : Natural + } + , address : + { country : Text + , state : Text + , city : Text + } + } + +let bernd : Profile = + { person = + { name = "Bernd Lauert" + , age = 67 + } + , address = + { country = "Deutschland" + , state = "Bayern" + , city = "Augsburg" + } + } + +let augsburg : Text = bernd.address.city + +{- Enum-Alternativen beginnen konventionell auch mit einem + Großbuchstaben. Das wird ebenfalls nicht erzwungen. +-} +let DNA : Type = < Adenine | Cytosine | Guanine | Thymine > + +let dnaSequence : List DNA = [ DNA.Thymine, DNA.Guanine, DNA.Guanine ] + +let compactDNASequence : List DNA = + let a = DNA.Adenine + let c = DNA.Cytosine + let g = DNA.Guanine + let t = DNA.Thymine + in [ c, t, t, a, t, c, g, g, c ] + +-- Enums werden transformiert, indem man einen Record mit einem Feld +-- pro Alternative angibt. +let theLetterG : Text = + merge + { Adenine = "A" + , Cytosine = "C" + , Guanine = "G" + , Thymine = "T" + } + DNA.Guanine + +let presentOptionalValue : Optional Natural = Some 1 + +let absentOptionalValue : Optional Natural = None Natural + +let points : List { x : Double, y : Double } = + [ { x = 1.1, y = -4.2 } + , { x = 4.4, y = -3.0 } + , { x = 8.2, y = -5.5 } + ] + +{- `Natural -> List Natural` ist der Funktionstyp mit Eingabetyp + `Natural` und Ausgabetyp `List Natural`. + + Alle Funktionen in Dhall sind Anonyme Funktionen (aka. „Lambdas“), + denen man optional einen Namen geben kann. + + Die folgende Funktion beispielsweise ist äquivalent zu diesem + Python Code: + + lambda n : [ n, n + 1 ] + + ... und diesem Javascript Code: + + function (n) { return [ n, n + 1 ]; } +-} +let exampleFunction : Natural -> List Natural = + \(n : Natural) -> [ n, n + 1 ] + +-- Dhall unterstützt auch Unicode-Syntax, aber dieses Tutorial nutzt +-- die ASCII-Syntax. +let unicodeFunction : Natural → List Natural = + λ(n : Natural) → [ n, n + 1 ] + +-- Funktionsargumente brauchen keine Klammern. +let exampleFunctionApplication : List Natural = + exampleFunction 2 + +let functionOfMultipleArguments : Natural -> Natural -> List Natural = + \(x : Natural) -> \(y : Natural) -> [ x, y ] + +let functionAppliedToMultipleArguments : List Natural = + functionOfMultipleArguments 2 3 + +{- Wie `exampleFunction`, aber wir geben dem Eingabetypen + einen Namen, `n`. +-} +let namedArgumentType : forall (n : Natural) -> List Natural = + \(n : Natural) -> [ n, n + 1 ] + +{- Bekommt der Eingabetyp einen Namen, kann man ihn weiter hinten in + der gleichen Typdefinition wiederverwenden. + + Das ermöglicht Funktionen, die mit mehr als einem Eingabetypen + arbeiten können (aka. „polymorphe“ Funktionen). +-} +let duplicate : forall (a : Type) -> a -> List a = + \(a : Type) -> \(x : a) -> [ x, x ] + +let duplicatedNumber : List Natural = + duplicate Natural 2 + +let duplicatedBool : List Bool = + duplicate Bool False + +{- Die Sprache hat auch eine handvoll eingebauter polymorpher + Funktionen, wie zum Beispiel: + + List/head : forall (a : Type) -> List a -> Optional a +-} +let firstPrime : Optional Natural = List/head Natural somePrimes + +let functionOfARecord : { x : Natural, y : Natural } -> List Natural = + \(args : { x : Natural, y : Natural }) -> [ args.x, args.y ] + +let functionAppliedToARecord : List Natural = + functionOfARecord { x = 2, y = 5 } + +{- Alle Typkonversionen sind explizit. + + `Natural/show` ist eine eingebaute Funktion mit dem Typ: + + Natural/show : Natural -> Text + + ... welche `Natural`s in ihre `Text`-Repräsentation konvertiert. +-} +let typeConversion : Natural -> Text = + \(age : Natural) -> "Ich bin ${Natural/show age} Jahre alt!" + +-- Ein „Template“ ist einfach eine Funktion mit Ausgabetyp `Text`. +let mitLicense : { year : Natural, copyrightHolder : Text } -> Text = + \(args : { year : Natural, copyrightHolder : Text }) -> +'' +Copyright ${Natural/show args.year} ${args.copyrightHolder} + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +'' + +-- Template-Instanziierung ist das gleiche wie Funktionsanwendung. +let templatedLicense : Text = + mitLicense { year = 2019, copyrightHolder = "Jane Smith" } + +{- Expressions können via URL importiert werden. + + Ähnlich wie in Bash kann man Code aus dem lokalen Dateisystem + importieren (wird nicht gezeigt). + + Sicherheitsbewusste Nutzer können via URLs importierte Expressions + mit einem semantischen Integritätscheck versehen („pinnen“). + Für gepinnte Imports wird der Dhall-Interpreter jeden Versuch + vereiteln, auf der Remote-Seite die Expression zu manipulieren. + Jedoch werden Änderungen, die den Inhalt der importierten + Expression nicht verändern trotzdem akzeptiert. + + Auf diese Weise gepinnte Expressions werden auch in einem + Content-Adressable Store lokal gecached (standardmäßig in + `~/.cache/dhall`). +-} +let Natural/sum : List Natural -> Natural = + https://prelude.dhall-lang.org/Natural/sum + sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037 + +let twentyEight : Natural = Natural/sum somePrimes + +-- Ein „Paket“ ist einfach ein (möglicherweise verschachtelter) +-- Record, den man importiert. +let Prelude = https://prelude.dhall-lang.org/package.dhall + +let false : Bool = Prelude.Bool.not True + +-- Durch das Anhängen von `as Text` wird eine Datei verbatim +-- importiert und nicht als Dhall-Code interpretiert. +let sourceCode : Text = https://prelude.dhall-lang.org/Bool/not as Text + +-- Environment-Variablen können auch imortiert werden. +let presentWorkingDirectory = env:PWD as Text + +-- Mit `?` kann man eine “Fallback-Expression” angeben, für den Fall +-- dass ein Import fehlschlägt. +let home : Optional Text = Some env:HOME ? None Text + +-- Fallback-Expressions können auch alternative Imports enthalten. +let possiblyCustomPrelude = + env:DHALL_PRELUDE + ? https://prelude.dhall-lang.org/package.dhall + +{- Ein ausführliches Beispiel, welches mithilfe der + `generate`-Funktion eine Konfiguration für 10 Build-User generiert: + + Prelude.List.generate + : Natural -> forall (a : Type) -> (Natural -> a) -> List a +-} +let buildUsers = + let makeUser = \(user : Text) -> + let home = "/home/${user}" + let privateKey = "${home}/.ssh/id_ed25519" + let publicKey = "${privateKey}.pub" + in { home = home + , privateKey = privateKey + , publicKey = publicKey + } + + let buildUser = + \(index : Natural) -> makeUser "build${Natural/show index}" + + let Config = + { home : Text + , privateKey : Text + , publicKey : Text + } + + in Prelude.List.generate 10 Config buildUser + +-- Alle Ergebnisse in einem großen Record +in { greeting = greeting + , fruits = fruits + , interpolation = interpolation + , multilineText = multilineText + , bool = bool + , annotation = annotation + , renderedBool = renderedBool + , naturalNumber = naturalNumber + , positiveInteger = positiveInteger + , negativeInteger = negativeInteger + , pi = pi + , `Avogadro's Number` = `Avogadro's Number` + , origin = origin + , somePrimes = somePrimes + , bernd = bernd + , augsburg = augsburg + , dnaSequence = dnaSequence + , compactDNASequence = compactDNASequence + , theLetterG = theLetterG + , presentOptionalValue = presentOptionalValue + , absentOptionalValue = absentOptionalValue + , points = points + , exampleFunction = exampleFunction + , unicodeFunction = unicodeFunction + , exampleFunctionApplication = exampleFunctionApplication + , functionOfMultipleArguments = functionOfMultipleArguments + , functionAppliedToMultipleArguments = functionAppliedToMultipleArguments + , namedArgumentType = namedArgumentType + , duplicate = duplicate + , duplicatedNumber = duplicatedNumber + , duplicatedBool = duplicatedBool + , firstPrime = firstPrime + , functionOfARecord = functionOfARecord + , functionAppliedToARecord = functionAppliedToARecord + , typeConversion = typeConversion + , mitLicense = mitLicense + , templatedLicense = templatedLicense + , twentyEight = twentyEight + , false = false + , sourceCode = sourceCode + , presentWorkingDirectory = presentWorkingDirectory + , home = home + , buildUsers = buildUsers + } +``` + +Mehr Infos und Lernmaterialien gibt es auf der offiziellen Website +(Englisch), auf der man Dhall auf im Browser ausprobieren kann: + +* [https://dhall-lang.org](http://dhall-lang.org/) diff --git a/de-de/git-de.html.markdown b/de-de/git-de.html.markdown index 7c68d785..0896f513 100644 --- a/de-de/git-de.html.markdown +++ b/de-de/git-de.html.markdown @@ -49,7 +49,7 @@ Ein Repository besteht in Git aus dem .git-Verzeichnis und dem Arbeitsverzeichni ### .git-Verzeichnis (Teil des Repositorys) -Das .git-Verzeichnis enthält alle Einstellung, Logs, Branches, den HEAD und mehr. +Das .git-Verzeichnis enthält alle Einstellungen, Logs, Branches, den HEAD und mehr. [Ausführliche Übersicht](http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html) ### Arbeitsverzeichnis (Teil des Repositorys) diff --git a/de-de/html-de.html.markdown b/de-de/html-de.html.markdown index 0bf58f9c..8b5597e7 100644 --- a/de-de/html-de.html.markdown +++ b/de-de/html-de.html.markdown @@ -50,10 +50,10 @@ Dieser Artikel ist bedacht darauf, nur HTML Syntax und nützliche Tipps zu geben <!-- Danach startet sie mit einem Öffnungtag <html>. --> <html> -<!-- Dieser wird am Ende der Datei mit</html> geschlossen. --> +<!-- Dieser wird am Ende der Datei mit </html> geschlossen. --> </html> -<!-- Nichts sollte nach diesen finalen Tag erscheinen. --> +<!-- Nichts sollte nach diesem finalen Tag erscheinen. --> <!-- Dazwischen (Zwischen dem Öffnungs- und Schließungstag <html></html>) finden wir: --> @@ -65,13 +65,13 @@ Dieser Artikel ist bedacht darauf, nur HTML Syntax und nützliche Tipps zu geben </head> <!-- Nach dem <head> Bereich findet sich der <body> Tag --> -<!-- Bis zu diesen Punkt wird nichts im Browerfenster angezeigt. --> -<!-- Wir müssen den Body mit dem Inhalt füllen der angezeigt werden soll. --> +<!-- Bis zu diesem Punkt wird nichts im Browerfenster angezeigt. --> +<!-- Wir müssen den Body mit dem Inhalt füllen, der angezeigt werden soll. --> <body> <h1>Hallo, Welt!</h1> <!-- Der h1 Tag erstellt einen Titel. --> <!-- Es gibt auch Untertitel für <h1> von den wichtigsten <h2> zu den Unwichtigsten (h6). --> - <a href = "http://codepen.io/anon/pen/xwjLbZ">Komm, schaue was das zeigt</a> <!-- Eine URL wird zum Hyperlink, wenn es das Attribut href="" --> + <a href = "http://codepen.io/anon/pen/xwjLbZ">Komm, schaue was das zeigt</a> <!-- Eine URL wird zum Hyperlink, wenn es das Attribut href="" hat --> <p>Das ist ein Absatz.</p> <!-- Der Tag <p> lässt uns Text auf die HTML Seite hinzufügen. --> <p>Das ist ein anderer Absatz.</p> <ul> <!-- Der <ul> Tag erstellt eine Aufzählungsliste. --> @@ -93,12 +93,12 @@ Dieser Artikel ist bedacht darauf, nur HTML Syntax und nützliche Tipps zu geben <!-- Es ist ebenso möglich eine Tabelle zu erstellen. --> <table> <!-- Wir öffnen ein <table> Element. --> - <tr> <!-- <tr> erlaubt es uns Reihe zu erstellen. --> - <th>Erster Tabellenkopf</th> <!-- <th> erlaubt es uns der Tabelle einen Titel zu geben. --> + <tr> <!-- <tr> erlaubt es uns, Reihen zu erstellen. --> + <th>Erster Tabellenkopf</th> <!-- <th> erlaubt es uns, der Tabelle einen Titel zu geben. --> <th>Zweiter Tabllenkopf</th> </tr> <tr> - <td>Erste Zeile, erste Spalte</td> <!-- <td> erlaubt es eine Tabellenzelle zu erstellen. --> + <td>Erste Zeile, erste Spalte</td> <!-- <td> erlaubt es, eine Tabellenzelle zu erstellen. --> <td>Erste Zeile, zweite Spalte</td> </tr> <tr> diff --git a/de-de/java-de.html.markdown b/de-de/java-de.html.markdown index e8ac5bda..e52087ec 100644 --- a/de-de/java-de.html.markdown +++ b/de-de/java-de.html.markdown @@ -477,7 +477,7 @@ Für tiefergreifende Fragen ist Google der beste Startpunkt. * [Generics](http://docs.oracle.com/javase/tutorial/java/generics/index.html) -* [Java Code Conventions](http://www.oracle.com/technetwork/java/codeconv-138413.html) +* [Java Code Conventions](https://www.oracle.com/technetwork/java/codeconventions-150003.pdf) **Online Tutorials** diff --git a/de-de/javascript-de.html.markdown b/de-de/javascript-de.html.markdown index f3917506..f817ee9f 100644 --- a/de-de/javascript-de.html.markdown +++ b/de-de/javascript-de.html.markdown @@ -1,7 +1,7 @@ ---
language: javascript
contributors:
- - ["Adam Brenecki", "http://adam.brenecki.id.au"]
+ - ["Leigh Brenecki", "https://leigh.net.au"]
translators:
- ["ggb", "http://www.ideen-und-soehne.de"]
filename: learnjavascript-de.js
@@ -13,7 +13,7 @@ JavaScript wurde im Jahr 1995 von Brendan Eich bei Netscape entwickelt. Ursprün Dabei ist JavaScript inzwischen nicht mehr auf Browser beschränkt: Node.js, ein Projekt, das eine eigene Laufzeitumgebung auf Grundlage von Google Chromes V8 mitbringt, wird derzeit immer populärer.
-Feedback ist herzlich Willkommen! Der ursprüngliche Autor ist unter [@adambrenecki](https://twitter.com/adambrenecki) oder [adam@brenecki.id.au](mailto:adam@brenecki.id.au) zu erreichen. Der Übersetzer unter [gregorbg@web.de](mailto:gregorbg@web.de).
+Feedback ist herzlich Willkommen! Der ursprüngliche Autor ist unter [@excitedleigh](https://twitter.com/excitedleigh) oder [l@leigh.net.au](mailto:l@leigh.net.au) zu erreichen. Der Übersetzer unter [gregorbg@web.de](mailto:gregorbg@web.de).
```js
// Kommentare werden wie in C gesetzt: Einzeilige Kommentare starten mit zwei
diff --git a/de-de/latex-de.html.markdown b/de-de/latex-de.html.markdown index ee9c6e3e..8a952b15 100644 --- a/de-de/latex-de.html.markdown +++ b/de-de/latex-de.html.markdown @@ -39,13 +39,13 @@ filename: latex-de.tex % Dieses Kommando kann man später benutzen. \newcommand{\comment}[1]{} -% Es können durchaus noch weitere Optione für das Dokument gesetzt werden! +% Es können durchaus noch weitere Optionen für das Dokument gesetzt werden! \author{Chaitanya Krishna Ande, Colton Kohnke \& Sricharan Chiruvolu} \date{\today} \title{Learn \LaTeX\ in Y Minutes!} % Nun kann's losgehen mit unserem Dokument. -% Alles vor dieser Zeile wird die Preamble genannt. +% Alles vor dieser Zeile wird die Präambel genannt. \begin{document} \comment{ @@ -62,7 +62,7 @@ filename: latex-de.tex % Inhalt erscheinen. % Dieser Befehl ist in den Dokumentenklassen article und report verfügbar. \begin{abstract} - \LaTeX -Documentation geschrieben in \LaTeX ! Wie ungewöhnlich und garantiert nicht meine Idee! + \LaTeX -Dokumentation geschrieben in \LaTeX ! Wie ungewöhnlich und garantiert nicht meine Idee! \end{abstract} % Section Befehle sind intuitiv. @@ -113,7 +113,7 @@ anderen Wissenschaften. Und deswegen müssen wir in der Lage sein, spezielle Symbole zu unserem Paper hinzuzufügen! \\ Mathe kennt sehr viele Symbole, viel mehr als auf einer Tastatur zu finden sind; -Symbole für Mengen und relationen, Pfeile, Operatoren und Griechische Buchstaben, +Symbole für Mengen und Relationen, Pfeile, Operatoren und Griechische Buchstaben, um nur ein paar zu nennen.\\ Mengen und Relationen spielen eine sehr wichtige Rolle in vielen mathematischen diff --git a/de-de/make-de.html.markdown b/de-de/make-de.html.markdown index cf90dc29..1bae332c 100644 --- a/de-de/make-de.html.markdown +++ b/de-de/make-de.html.markdown @@ -11,14 +11,14 @@ lang: de-de ---
Eine Makefile definiert einen Graphen von Regeln um ein Ziel (oder Ziele)
-zu erzeugen. Es dient dazu die geringste Menge an Arbeit zu verrichten um
-ein Ziel in einklang mit dem Quellcode zu bringen. Make wurde berühmterweise
+zu erzeugen. Es dient dazu, die geringste Menge an Arbeit zu verrichten um
+ein Ziel in Einklang mit dem Quellcode zu bringen. Make wurde berühmterweise
von Stuart Feldman 1976 übers Wochenende geschrieben. Make ist noch immer
-sehr verbreitet (vorallem im Unix umfeld) obwohl es bereits sehr viel
+sehr verbreitet (vorallem im Unix Umfeld) obwohl es bereits sehr viel
Konkurrenz und Kritik zu Make gibt.
-Es gibt eine vielzahl an Varianten von Make, dieser Artikel beschäftig sich
-mit der Version GNU Make. Diese Version ist standard auf Linux.
+Es gibt eine Vielzahl an Varianten von Make, dieser Artikel beschäftigt sich
+mit der Version GNU Make. Diese Version ist Standard auf Linux.
```make
@@ -44,14 +44,15 @@ file0.txt: # die erste Regel ist die Standard-Regel.
-# Diese Regel wird nur abgearbeitet wenn file0.txt aktueller als file1.txt ist.
+# Diese Regel wird nur abgearbeitet, wenn file0.txt aktueller als file1.txt ist.
file1.txt: file0.txt
cat file0.txt > file1.txt
# Verwende die selben Quoting-Regeln wie die Shell
@cat file0.txt >> file1.txt
# @ unterdrückt die Ausgabe des Befehls an stdout.
-@echo 'hello'
- # - bedeutet das Make die Abarbeitung fortsetzt auch wenn Fehler passieren.
+ # - bedeutet, dass Make die Abarbeitung fortsetzt auch wenn Fehler
+ # passieren.
# Versuche `make file1.txt` auf der Kommandozeile.
# Eine Regel kann mehrere Ziele und mehrere Voraussetzungen haben.
@@ -59,7 +60,7 @@ file2.txt file3.txt: file0.txt file1.txt touch file2.txt
touch file3.txt
-# Make wird sich beschweren wenn es mehrere Rezepte für die gleiche Regel gibt.
+# Make wird sich beschweren, wenn es mehrere Rezepte für die gleiche Regel gibt.
# Leere Rezepte zählen nicht und können dazu verwendet werden weitere
# Voraussetzungen hinzuzufügen.
@@ -67,8 +68,8 @@ file2.txt file3.txt: file0.txt file1.txt # Phony-Ziele
#-----------------------------------------------------------------------
-# Ein Phony-Ziel ist ein Ziel das keine Datei ist.
-# Es wird nie aktuell sein, daher wird Make immer versuchen es abzuarbeiten
+# Ein Phony-Ziel ist ein Ziel, das keine Datei ist.
+# Es wird nie aktuell sein, daher wird Make immer versuchen, es abzuarbeiten
all: maker process
# Es ist erlaubt Dinge ausserhalb der Reihenfolge zu deklarieren.
@@ -89,14 +90,14 @@ ex0.txt ex1.txt: maker # Automatische Variablen & Wildcards
#-----------------------------------------------------------------------
-process: file*.txt # Eine Wildcard um Dateinamen zu Vergleichen
+process: file*.txt # Eine Wildcard um Dateinamen zu vergleichen
@echo $^ # $^ ist eine Variable die eine Liste aller
# Voraussetzungen enthält.
@echo $@ # Namen des Ziels ausgeben.
#(Bei mehreren Ziel-Regeln enthält $@ den Verursacher der Abarbeitung
#der Regel.)
@echo $< # Die erste Voraussetzung aus der Liste
- @echo $? # Nur die Voraussetzungen die nicht aktuell sind.
+ @echo $? # Nur die Voraussetzungen, die nicht aktuell sind.
@echo $+ # Alle Voraussetzungen inklusive Duplikate (nicht wie Üblich)
#@echo $| # Alle 'order only' Voraussetzungen
@@ -114,20 +115,20 @@ process: ex1.txt file0.txt %.png: %.svg
inkscape --export-png $^
-# Muster-Vergleichs-Regeln werden nur abgearbeitet wenn make entscheidet das Ziel zu
-# erzeugen
+# Muster-Vergleichs-Regeln werden nur abgearbeitet, wenn make entscheidet das
+# Ziel zu erzeugen
# Verzeichnis-Pfade werden normalerweise bei Muster-Vergleichs-Regeln ignoriert.
# Aber make wird versuchen die am besten passende Regel zu verwenden.
small/%.png: %.svg
inkscape --export-png --export-dpi 30 $^
-# Make wird die letzte Version einer Muster-Vergleichs-Regel verwenden die es
+# Make wird die letzte Version einer Muster-Vergleichs-Regel verwenden, die es
# findet.
%.png: %.svg
@echo this rule is chosen
-# Allerdings wird make die erste Muster-Vergleicher-Regel verwenden die das
+# Allerdings wird make die erste Muster-Vergleicher-Regel verwenden, die das
# Ziel erzeugen kann.
%.png: %.ps
@echo this rule is not chosen if *.svg and *.ps are both present
@@ -171,7 +172,7 @@ name4 ?= Jean # nicht gibt.
override name5 = David
-# Verhindert das Kommando-Zeilen Argumente diese Variable ändern können.
+# Verhindert, dass Kommando-Zeilen Argumente diese Variable ändern können.
name4 +=grey
# Werte an eine Variable anhängen (inkludiert Leerzeichen).
@@ -179,9 +180,9 @@ name4 +=grey # Muster-Spezifische Variablen Werte (GNU Erweiterung).
echo: name2 = Sara # Wahr innerhalb der passenden Regel und auch innerhalb
# rekursiver Voraussetzungen (ausser wenn es den Graphen zerstören
- # kann wenn es zu kompilizert wird!)
+ # kann, wenn es zu kompilizert wird!)
-# Ein paar Variablen die von Make automatisch definiert werden.
+# Ein paar Variablen, die von Make automatisch definiert werden.
echo_inbuilt:
echo $(CC)
echo ${CXX}
@@ -196,7 +197,7 @@ echo_inbuilt: # Variablen 2
#-----------------------------------------------------------------------
-# Der erste Typ von Variablen wird bei jeder verwendung ausgewertet.
+# Der erste Typ von Variablen wird bei jeder Verwendung ausgewertet.
# Das kann aufwendig sein, daher exisitert ein zweiter Typ von Variablen.
# Diese werden nur einmal ausgewertet. (Das ist eine GNU make Erweiterung)
@@ -215,7 +216,7 @@ var4 ::= good night # Funktionen
#-----------------------------------------------------------------------
-# Make verfügt über eine vielzahl von Funktionen.
+# Make verfügt über eine Vielzahl von Funktionen.
sourcefiles = $(wildcard *.c */*.c)
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
diff --git a/de-de/markdown-de.html.markdown b/de-de/markdown-de.html.markdown index cccf5e68..729e883c 100644 --- a/de-de/markdown-de.html.markdown +++ b/de-de/markdown-de.html.markdown @@ -144,7 +144,7 @@ indem du eine Zeile mit vier Leerzeichen oder einem Tabulator einrückst --> puts item end -<!-- Innerhalb normalen Texts kannst du Code mit Backticks ` auszeichnen --> +<!-- Innerhalb normalen Texts kannst du Code mit Backticks \` auszeichnen --> Hermann hatte nicht die leiseste Ahnung, was dieses `go_to()` bedeuten könnte! diff --git a/de-de/nix-de.html.markdown b/de-de/nix-de.html.markdown index 79b60d20..ea02e81d 100644 --- a/de-de/nix-de.html.markdown +++ b/de-de/nix-de.html.markdown @@ -8,11 +8,11 @@ translators: lang: de-de --- -Nix ist eine simple funktionale Programmiersprache, die für den +Nix ist eine simple funktionale Programmiersprache, die für den [Nix package manager](https://nixos.org/nix/) und [NixOS](https://nixos.org/) entwickelt wurde. -Du kannst Nix Ausdrücke evaluieren mithilfe von +Du kannst Nix Ausdrücke evaluieren mithilfe von [nix-instantiate](https://nixos.org/nix/manual/#sec-nix-instantiate) oder [`nix-repl`](https://github.com/edolstra/nix-repl). @@ -24,7 +24,7 @@ with builtins; [ # Inline Kommentare sehen so aus. - /* Multizeilen Kommentare + /* Multizeilen Kommentare sehen so aus. */ @@ -61,7 +61,7 @@ with builtins; [ "String Literale sind in Anführungszeichen." " - String Literale können mehrere + String Literale können mehrere Zeilen umspannen. " @@ -95,7 +95,7 @@ with builtins; [ tutorials/learn.nix #=> /the-base-path/tutorials/learn.nix - # Ein Pfad muss mindestens einen Schrägstrich enthalten. Ein Pfad für eine + # Ein Pfad muss mindestens einen Schrägstrich enthalten. Ein Pfad für eine # Datei im selben Verzeichnis benötigt ein ./ Präfix. ./learn.nix #=> /the-base-path/learn.nix @@ -238,7 +238,7 @@ with builtins; [ #=> { d = 2; e = 3; } # Die Nachkommen eines Attributs können in diesem Feld nicht zugeordnet werden, wenn - # das Attribut selbst nicht zugewiesen wurde. + # das Attribut selbst nicht zugewiesen wurde. { a = { b = 1; }; a.c = 2; @@ -261,9 +261,9 @@ with builtins; [ #=> 7 # Die erste Linie diese Tutorials startet mit "with builtins;", - # weil builtins ein Set mit allen eingebauten + # weil builtins ein Set mit allen eingebauten # Funktionen (length, head, tail, filter, etc.) umfasst. - # Das erspart uns beispielsweise "builtins.length" zu schreiben, + # Das erspart uns beispielsweise "builtins.length" zu schreiben, # anstatt nur "length". @@ -305,7 +305,7 @@ with builtins; [ (tryEval (abort "foo")) #=> error: evaluation aborted with the following error message: ‘foo’ - # `assert` evaluiert zu dem gegebenen Wert, wenn die Bedingung wahr ist, sonst + # `assert` evaluiert zu dem gegebenen Wert, wenn die Bedingung wahr ist, sonst # löst es eine abfangbare Exception aus. (assert 1 < 2; 42) #=> 42 @@ -319,7 +319,7 @@ with builtins; [ #========================================= # Da die Wiederholbarkeit von Builds für den Nix Packetmanager entscheidend ist, - # werden in der Nix Sprache reine funktionale Elemente betont. Es gibt aber ein paar + # werden in der Nix Sprache reine funktionale Elemente betont. Es gibt aber ein paar # unreine Elemente. # Du kannst auf Umgebungsvariablen verweisen. (getEnv "HOME") @@ -355,4 +355,4 @@ with builtins; [ (https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55) * [Susan Potter - Nix Cookbook - Nix By Example] - (http://funops.co/nix-cookbook/nix-by-example/) + (https://ops.functionalalgebra.com/nix-by-example/) diff --git a/de-de/python-de.html.markdown b/de-de/python-de.html.markdown index d3e0fc26..337f1224 100644 --- a/de-de/python-de.html.markdown +++ b/de-de/python-de.html.markdown @@ -1,9 +1,10 @@ --- -language: python +language: Python contributors: - ["Louie Dinh", "http://ldinh.ca"] translators: - ["kultprok", "http:/www.kulturproktologie.de"] + - ["matthiaskern", "https://github.com/matthiaskern"] filename: learnpython-de.py lang: de-de --- @@ -11,13 +12,16 @@ lang: de-de Anmerkungen des ursprünglichen Autors: Python wurde in den frühen Neunzigern von Guido van Rossum entworfen. Es ist heute eine der beliebtesten Sprachen. Ich habe mich in Python wegen seiner syntaktischen Übersichtlichkeit verliebt. Eigentlich ist es ausführbarer Pseudocode. -Feedback ist herzlich willkommen! Ihr erreicht mich unter [@louiedinh](http://twitter.com/louiedinh) oder louiedinh [at] [google's email service] +Feedback ist herzlich willkommen! Ihr erreicht mich unter [@louiedinh](http://twitter.com/louiedinh) oder louiedinh [at] [google's email service]. -Hinweis: Dieser Beitrag bezieht sich besonders auf Python 2.7, er sollte aber auf Python 2.x anwendbar sein. Haltet Ausschau nach einem Rundgang durch Python 3, der bald erscheinen soll. +Hinweis: Dieser Beitrag bezieht sich implizit auf Python 3. Falls du lieber Python 2.7 lernen möchtest, schau [hier](http://learnxinyminutes.com/docs/pythonlegacy/) weiter. Beachte hierbei, +dass Python 2 als veraltet gilt und für neue Projekte nicht mehr verwendet werden sollte. ```python + # Einzeilige Kommentare beginnen mit einer Raute (Doppelkreuz) -""" Mehrzeilige Strings werden mit + +""" Mehrzeilige Strings werden mit drei '-Zeichen geschrieben und werden oft als Kommentare genutzt. """ @@ -33,15 +37,24 @@ Hinweis: Dieser Beitrag bezieht sich besonders auf Python 2.7, er sollte aber au 1 + 1 #=> 2 8 - 1 #=> 7 10 * 2 #=> 20 -35 / 5 #=> 7 -# Division ist ein wenig kniffliger. Ganze Zahlen werden ohne Rest dividiert -# und das Ergebnis wird automatisch abgerundet. -5 / 2 #=> 2 +# Außer Division, welche automatisch Gleitkommazahlen zurückgibt +35 / 5 # => 7.0 + +# Eine Division kann mit "//" für positive sowie negative Werte abgerundet werden. +5 // 3 # => 1 +5.0 // 3.0 # => 1.0 # funktioniert auch mit floats +-5 // 3 # => -2 +-5.0 // 3.0 # => -2.0 + +# Benutzt man eine Gleitkommazahl, ist auch das Ergebnis eine solche +3 * 2.0 # => 6.0 + +# Der Rest einer Division +7 % 3 # => 1 -# Um das zu ändern, müssen wir Gleitkommazahlen einführen und benutzen -2.0 # Das ist eine Gleitkommazahl -11.0 / 4.0 #=> 2.75 Ahhh...schon besser +# Potenz +2**4 # => 16 # Rangfolge wird mit Klammern erzwungen (1 + 3) * 2 #=> 8 @@ -54,6 +67,18 @@ False not True #=> False not False #=> True +# Boolesche Operatoren +# Hinweis: "and" und "or" müssen klein geschrieben werden +True and False #=> False +False or True #=> True + +# Für die Benutzung von Booleschen Operatoren und ganzen Zahlen +0 and 2 #=> 0 +-5 or 0 #=> -5 +0 == False #=> True +2 == True #=> False +1 == True #=> True + # Gleichheit ist == 1 == 1 #=> True 2 == 1 #=> False @@ -76,58 +101,59 @@ not False #=> True "Das ist ein String." 'Das ist auch ein String.' -# Strings können addiert werden! -"Hello " + "world!" #=> "Hello world!" +# Strings können auch addiert werden! Vermeide dies aber lieber. +"Hallo " + "Welt!" #=> "Hallo Welt!" +# Strings können ohne "+" addiert werden +"Hallo " "welt!" # => "Hallo Welt!" # Ein String kann wie eine Liste von Zeichen verwendet werden "Das ist ein String"[0] #=> 'D' -# Mit % können Strings formatiert werden, etwa so: -"%s können %s werden" % ("Strings", "interpoliert") +# .format kann Strings formatieren +"{} können {} werden".format("Strings", "formatiert") + +# Schneller geht das mit Wiederholungen +"{0} mag Spagetthi, {0} liebt es zu Schwimmen und ganz besonders mag {0} {1}".format("Hans", "Blattsalat") +#=> "Hans mag Spagetthi, Hans liebt es zu Schwimmen und ganz besonders mag Hans Blattsalat" -# Ein modernerer Weg, um Strings zu formatieren, ist die format-Methode. -# Diese Methode wird bevorzugt -"{0} können {1} werden".format("Strings", "formatiert") -# Wir können Schlüsselwörter verwenden, wenn wir nicht abzählen wollen. -"{name} will {food} essen".format(name="Bob", food="Lasagne") +# Die Formatierung kann auch mit `f-strings` oder formattierten Strings gemacht +# werden (ab Python 3.6+) +name = "Sandra" +f"Sie hat gesagt, ihr name sei {name}." # => Sie hat gesagt, ihr Name sei Sandra." +# Es ist möglich, andere Anweisungen innerhalb der geschweiften Klammern zu +# setzen, welche dann im Output des Strings angezeigt werden. +f"{name} ist {len(name)} Zeichen lang" # => Sandra ist 6 Zeichen lang. # None ist ein Objekt None #=> None # Verwendet nicht das Symbol für Gleichheit `==`, um Objekte mit None zu vergleichen -# Benutzt stattdessen `is` +# Benutzt stattdessen `is`. Dieser Operator testet Objektidentität "etc" is None #=> False None is None #=> True -# Der 'is'-Operator testet Objektidentität. Das ist nicht -# sehr nützlich, wenn wir mit primitiven Datentypen arbeiten, aber -# sehr nützlich bei Objekten. - # None, 0, und leere Strings/Listen werden alle als False bewertet. # Alle anderen Werte sind True -0 == False #=> True -"" == False #=> True - +bool(0) # => False +bool("") # => False +bool([]) #=> False +bool({}) #=> False #################################################### ## 2. Variablen und Collections #################################################### # Textausgabe ist sehr einfach -print "Ich bin Python. Schön, dich kennenzulernen!" - +print("Ich bin Python. Schön, dich kennenzulernen!") # Es gibt keinen Grund, Variablen vor der Zuweisung zu deklarieren. some_var = 5 # kleinschreibung_mit_unterstrichen entspricht der Norm some_var #=> 5 -# Das Ansprechen einer noch nicht deklarierte Variable löst eine Exception aus. +# Das Ansprechen einer noch nicht deklarierten Variable löst eine Exception aus. # Unter "Kontrollstruktur" kann noch mehr über # Ausnahmebehandlung erfahren werden. -some_other_var # Löst einen NameError aus - -# if kann als Ausdruck verwendet werden -"yahoo!" if 3 > 2 else 2 #=> "yahoo!" +some_unknown_var # Löst einen NameError aus # Listen speichern Sequenzen li = [] @@ -150,7 +176,7 @@ li[0] #=> 1 li[-1] #=> 3 # Bei Zugriffen außerhalb der Liste kommt es jedoch zu einem IndexError -li[4] # Raises an IndexError +li[4] # Verursacht einen IndexError # Wir können uns Ranges mit Slice-Syntax ansehen li[1:3] #=> [2, 4] @@ -158,6 +184,12 @@ li[1:3] #=> [2, 4] li[2:] #=> [4, 3] # Das Ende auslassen li[:3] #=> [1, 2, 4] +# Jeden Zweiten Eintrag auswählen +li[::2] # =>[1, 4] +# Eine umgekehrte Kopie zurückgeben +li[::-1] # => [3, 4, 2, 1] +# Jegliche Kombination dieser Syntax machen fortgeschrittene Slices möglich +# li[Start:Ende:Schritt] # Ein bestimmtes Element mit del aus der Liste entfernen del li[2] # li ist jetzt [1, 2, 3] @@ -174,7 +206,6 @@ li.extend(other_li) # Jetzt ist li [1, 2, 3, 4, 5, 6] # Die Länge der Liste mit len ermitteln len(li) #=> 6 - # Tupel sind wie Listen, nur unveränderlich. tup = (1, 2, 3) tup[0] #=> 1 @@ -190,11 +221,10 @@ tup[:2] #=> (1, 2) a, b, c = (1, 2, 3) # a ist jetzt 1, b ist jetzt 2 und c ist jetzt 3 # Tupel werden standardmäßig erstellt, wenn wir uns die Klammern sparen d, e, f = 4, 5, 6 -# Es ist kinderleicht zwei Werte zu tauschen -e, d = d, e # d is now 5 and e is now 4 +# Es ist kinderleicht, zwei Werte zu tauschen +e, d = d, e # d ist nun 5 und e ist nun 4 - -# Dictionarys (Wörterbucher) speichern Key-Value-Paare +# Dictionarys (Wörterbucher) speichern Schlüssel-Werte-Paare empty_dict = {} # Hier ein gefülltes Wörterbuch filled_dict = {"one": 1, "two": 2, "three": 3} @@ -203,15 +233,15 @@ filled_dict = {"one": 1, "two": 2, "three": 3} filled_dict["one"] #=> 1 # So holen wir alle Keys (Schlüssel) als Liste -filled_dict.keys() #=> ["three", "two", "one"] +list(filled_dict.keys()) #=> ["three", "two", "one"] # Hinweis - Die Reihenfolge von Schlüsseln in der Liste ist nicht garantiert. # Einzelne Resultate können anders angeordnet sein. # Alle Values (Werte) als Liste -filled_dict.values() #=> [3, 2, 1] +list(filled_dict.values()) #=> [3, 2, 1] # Hinweis - Hier gelten dieselben Einschränkungen für die Reihenfolge wie bei Schlüsseln. -# Das Vorhandensein eines Schlüssels im Wörterbuch mit in prüfen +# Das Vorhandensein eines Schlüssels im Wörterbuch mit "in" prüfen "one" in filled_dict #=> True 1 in filled_dict #=> False @@ -229,17 +259,23 @@ filled_dict.get("four", 4) #=> 4 filled_dict.setdefault("five", 5) #filled_dict["five"] wird auf 5 gesetzt filled_dict.setdefault("five", 6) #filled_dict["five"] ist noch immer 5 +# Einträge zu einem Wörterbuch hinzufügen +filled_dict.update({"four":4}) #=> {"one": 1, "two": 2, "three": 3, "four": 4} +#filled_dict["four"] = 4 # noch ein Weg, Werte hinzuzufügen + +# Schlüssel von einem Wörterbuch entfernen +del filled_dict["one"] # Entfert den Schlüssel "one" # Sets speichern Mengen empty_set = set() # Initialisieren wir ein Set mit ein paar Werten -some_set = set([1,2,2,3,4]) # some_set ist jetzt set([1, 2, 3, 4]) +some_set = {1, 1, 2, 2, 3, 4} # some_set ist jetzt {1, 2, 3, 4} -# Seit Python 2.7 kann {} benutzt werden, um ein Set zu erstellen -filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4} +# Neue Variablen können einer Menge gleichgesetzt werden +filled_set = some_set # Mehr Elemente hinzufügen -filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} +filled_set.add(5) # filled_set ist jetzt {1, 2, 3, 4, 5} # Schnittmengen werden mit & gebildet other_set = {3, 4, 5, 6} @@ -257,7 +293,7 @@ filled_set | other_set #=> {1, 2, 3, 4, 5, 6} #################################################### -## 3. Kontrollstruktur +## 3. Kontrollstruktur und Iteratoren #################################################### # Erstellen wir mal eine Variable @@ -266,11 +302,11 @@ some_var = 5 # Hier eine if-Anweisung. Die Einrückung ist in Python wichtig! # gibt "some_var ist kleiner als 10" aus if some_var > 10: - print "some_var ist viel größer als 10." + print("some_var ist viel größer als 10.") elif some_var < 10: # Dieser elif-Absatz ist optional. - print "some_var ist kleiner als 10." + print("some_var ist kleiner als 10.") else: # Das hier ist auch optional. - print "some_var ist tatsächlich 10." + print("some_var ist tatsächlich 10.") """ @@ -281,9 +317,9 @@ Ausgabe: maus ist ein Säugetier """ for animal in ["hund", "katze", "maus"]: - # Wir können Strings mit % formatieren - print "%s ist ein Säugetier" % animal - + # Wir können Strings mit format() formatieren + print("{} ist ein Säugetier".format(animal)) + """ `range(Zahl)` gibt eine null-basierte Liste bis zur angegebenen Zahl wieder Ausgabe: @@ -293,7 +329,18 @@ Ausgabe: 3 """ for i in range(4): - print i + print(i) + +""" +"range(unten, oben)" gibt eine Liste von der unteren Zahl bis zur oberen Zahl aus +Ausgabe: + 4 + 5 + 6 + 7 +""" +for i in range(4, 8): + print(i) """ While-Schleifen laufen, bis eine Bedingung erfüllt ist. @@ -305,18 +352,59 @@ Ausgabe: """ x = 0 while x < 4: - print x + print(x) x += 1 # Kurzform für x = x + 1 # Ausnahmebehandlung mit einem try/except-Block - -# Funktioniert in Python 2.6 und höher: try: # Mit raise wird ein Fehler ausgegeben raise IndexError("Das hier ist ein Index-Fehler") except IndexError as e: pass # Pass ist nur eine no-op. Normalerweise würden wir hier den Fehler klären. +except (TypeError, NameError): + pass # Mehrere Fehler können zusammen geklärt werden, falls erforderlich. +else: # Optional, hinter allen except-Blöcken + print("Keine Probleme!") # Wird nur ausgeführt, wenn keine Ausnahmen aufgetreten sind +finally: # Wird immer ausgeführt + print("Hier können wir Ressourcen aufräumen") + +# alternativ zu einem try/finally Block um Aufzuräumen: +with open("meineDatei.txt") as f: + for line in f: + print(line) + +# Python bietet ein fundamentales Konzept der Iteration. +# Das Objekt, auf das die Iteration, also die Wiederholung einer Methode +# angewandt wird, heißt auf Englisch "iterable". +# Die range Methode gibt ein solches Objekt aus. + +filled_dict = {"one": 1, "two": 2, "three": 3} +our_iterable = filled_dict.keys() +print(our_iterable) #=> range(1,10). Dies ist ein "iterable" Objekt. + +# Über dieses können wir auch iterieren +for i in our_iterable: + print(i) # Gibt one, two, three aus + +# Allerdings können wir die einzelnen Elemente nicht mit ihrem Index ausgeben +our_iterable[1] # TypeError +# Ein iterable ist ein Objekt, das weiß wie es einen Iteratoren erschafft. +our_iterator = iter(our_iterable) + +# Unser Iterator ist ein Objekt, das sich merkt, welchen Status es gerade hat +# während wir durch es gehen. Das jeweils nächste Objekt bekommen wir mit "next()" +next(our_iterator) #=> "one" + +# Es hält den vorherigen Status +next(our_iterator) #=> "two" +next(our_iterator) #=> "three" + +# Nachdem alle Daten ausgegeben worden sind, kommt eine StopIterator Ausnahme zurück +next(our_iterator) # Gibt StopIteration aus + +# Alle Elemente können mit "list()" ausgegeben werden +list(filled_dict.keys()) #=> ["one", "two", "three"] #################################################### ## 4. Funktionen @@ -324,7 +412,7 @@ except IndexError as e: # Mit def neue Funktionen erstellen def add(x, y): - print "x ist %s und y ist %s" % (x, y) + print("x ist %s und y ist %s" % (x, y)) return x + y # Werte werden mit return zurückgegeben # Funktionen mit Parametern aufrufen @@ -348,10 +436,10 @@ def keyword_args(**kwargs): # Rufen wir es mal auf, um zu sehen, was passiert keyword_args(big="foot", loch="ness") #=> {"big": "foot", "loch": "ness"} -# Wir können beides gleichzeitig machem, wenn wir wollen +# Wir können beides gleichzeitig machen, wenn wir wollen def all_the_args(*args, **kwargs): - print args - print kwargs + print(args) + print(kwargs) """ all_the_args(1, 2, a=3, b=4) Ausgabe: (1, 2) @@ -366,6 +454,25 @@ all_the_args(*args) # äquivalent zu foo(1, 2, 3, 4) all_the_args(**kwargs) # äquivalent zu foo(a=3, b=4) all_the_args(*args, **kwargs) # äquivalent zu foo(1, 2, 3, 4, a=3, b=4) + +# Anwendungsbereich von Funktionen +x = 5 + +def setX(num): + # lokale Variable x ist nicht die globale Variable x + x = num # => 43 + print (x) # => 43 + +def setGlobalX(num): + global x + print (x) # => 5 + x = num # globale Variable x ist jetzt 6 + print (x) # => 6 + +setX(43) +setGlobalX(6) + + # Python hat First-Class-Funktionen def create_adder(x): def adder(y): @@ -403,7 +510,7 @@ class Human(object): # Eine Instanzmethode. Alle Methoden erhalten self als erstes Argument. def say(self, msg): - return "%s: %s" % (self.name, msg) + return "{name}: {message}".format(name=self.name, message=msg) # Eine Klassenmethode wird von allen Instanzen geteilt. # Sie werden mit der aufrufenden Klasse als erstem Argument aufgerufen @@ -419,10 +526,10 @@ class Human(object): # Eine Instanz einer Klasse erstellen i = Human(name="Ian") -print i.say("hi") # gibt "Ian: hi" aus +print(i.say("hi")) # gibt "Ian: hi" aus j = Human("Joel") -print j.say("hello") #gibt "Joel: hello" aus +print(j.say("hello")) #gibt "Joel: hello" aus # Rufen wir mal unsere Klassenmethode auf i.get_species() #=> "H. sapiens" @@ -442,12 +549,12 @@ Human.grunt() #=> "*grunt*" # Wir können Module importieren import math -print math.sqrt(16) #=> 4.0 +print(math.sqrt(16)) #=> 4.0 # Wir können auch nur spezielle Funktionen eines Moduls importieren from math import ceil, floor -print ceil(3.7) #=> 4.0 -print floor(3.7) #=> 3.0 +print(ceil(3.7)) #=> 4.0 +print(floor(3.7)) #=> 3.0 # Wir können auch alle Funktionen eines Moduls importieren # Warnung: Dies wird nicht empfohlen @@ -458,7 +565,7 @@ import math as m math.sqrt(16) == m.sqrt(16) #=> True # Module sind in Python nur gewöhnliche Dateien. Wir -# können unsere eigenen schreiben und importieren. Der Name des +# können unsere eigenen schreiben und importieren. Der Name des # Moduls ist der Dateiname. # Wir können auch die Funktionen und Attribute eines @@ -466,6 +573,56 @@ math.sqrt(16) == m.sqrt(16) #=> True import math dir(math) +#################################################### +## 7. Fortgeschritten +#################################################### + +# Generatoren helfen, um Code schnell und einfach zu schreiben +def double_numbers(iterable): + for i in iterable: + yield i + i + +# Ein Generator erschafft Werte spontan +# Statt alle Werte auf einmal, wird bei jeder Iteration einer erschaffen. +# iteration. Das heißt, Werte größer als 15 werden nicht behandelt. +# Die range-Methode ist auch ein Generator. Im Fall einer Liste von 1-900000000 +# würde das sehr viel Zeit in Anspruch nehmen. +# Wenn wir eine Variable mit einem Namen erschaffen wollen, das +# normalerweise mit einem Python - Schlüsselwort kollidieren würde, +# benutzen wir einen Unterstrich nach dem Wort. +range_ = range(1, 900000000) +# Alle Nummern bis zu einem Ergebnis von >=30 werden verdoppelt +for i in double_numbers(range_): + print(i) + if i >= 30: + break + +# Dekoratoren +# In diesem Beispiel die Methode beg umwickelt say +# Beim Aufruf von beg, wird say aufgerufen +# Falls say_please true ist, ändert sich die ausgegebene Nachricht +from functools import wraps + + +def beg(target_function): + @wraps(target_function) + def wrapper(*args, **kwargs): + msg, say_please = target_function(*args, **kwargs) + if say_please: + return "{} {}".format(msg, "Please! I am poor :(") + return msg + + return wrapper + + +@beg +def say(say_please=False): + msg = "Can you buy me a beer?" + return msg, say_please + + +print(say()) # Can you buy me a beer? +print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( ``` @@ -473,15 +630,18 @@ dir(math) ### Kostenlos online (Englisch) +* [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) * [Dive Into Python](http://www.diveintopython.net/) -* [The Official Docs](http://docs.python.org/2.6/) +* [Ideas for Python Projects](http://pythonpracticeprojects.com) +* [The Official Docs](http://docs.python.org/3/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) -* [Python Module of the Week](http://pymotw.com/2/) +* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) +* [Python Course](http://www.python-course.eu/index.php) +* [First Steps With Python](https://realpython.com/learn/python-first-steps/) ### Totholz (Englisch) * [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) * [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) * [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) - diff --git a/de-de/python3-de.html.markdown b/de-de/python3-de.html.markdown deleted file mode 100644 index c383d742..00000000 --- a/de-de/python3-de.html.markdown +++ /dev/null @@ -1,655 +0,0 @@ ---- -language: python3 -contributors: - - ["Louie Dinh", "http://ldinh.ca"] -translators: - - ["kultprok", "http:/www.kulturproktologie.de"] - - ["matthiaskern", "https://github.com/matthiaskern"] -filename: learnpython3-de.py -lang: de-de ---- - -Anmerkungen des ursprünglichen Autors: -Python wurde in den frühen Neunzigern von Guido van Rossum entworfen. Es ist heute eine der beliebtesten Sprachen. Ich habe mich in Python wegen seiner syntaktischen Übersichtlichkeit verliebt. Eigentlich ist es ausführbarer Pseudocode. - -Feedback ist herzlich willkommen! Ihr erreicht mich unter [@louiedinh](http://twitter.com/louiedinh) oder louiedinh [at] [google's email service]. - -Hinweis: Dieser Beitrag bezieht sich insplizit auf Python 3. Falls du lieber Python 2.7 lernen möchtest, schau [hier](http://learnxinyminutes.com/docs/python/) weiter. - -```python - -# Einzeilige Kommentare beginnen mit einer Raute (Doppelkreuz) - -""" Mehrzeilige Strings werden mit - drei '-Zeichen geschrieben und werden - oft als Kommentare genutzt. -""" - -#################################################### -## 1. Primitive Datentypen und Operatoren -#################################################### - -# Die Zahlen -3 #=> 3 - -# Mathematik funktioniert so, wie man das erwartet -1 + 1 #=> 2 -8 - 1 #=> 7 -10 * 2 #=> 20 - -# Außer Division, welche automatisch Gleitkommazahlen zurückgibt -35 / 5 # => 7.0 - -# Eine Division kann mit "//" für positive sowie negative Werte abgerundet werden. -5 // 3 # => 1 -5.0 // 3.0 # => 1.0 # works on floats too --5 // 3 # => -2 --5.0 // 3.0 # => -2.0 - -# Benutzt man eine Gleitkommazahl, ist auch das Ergebnis eine solche -3 * 2.0 # => 6.0 - -# Der Rest einer Division -7 % 3 # => 1 - -# Potenz -2**4 # => 16 - -# Rangfolge wird mit Klammern erzwungen -(1 + 3) * 2 #=> 8 - -# Boolesche Ausdrücke sind primitive Datentypen -True -False - -# Mit not wird negiert -not True #=> False -not False #=> True - -# Boolesche Operatoren -# Hinweis: "and" und "or" müssen klein geschrieben werden -True and False #=> False -False or True #=> True - -# Für die Benutzung von Booleschen Operatoren und ganzen Zahlen -0 and 2 #=> 0 --5 or 0 #=> -5 -0 == False #=> True -2 == True #=> False -1 == True #=> True - -# Gleichheit ist == -1 == 1 #=> True -2 == 1 #=> False - -# Ungleichheit ist != -1 != 1 #=> False -2 != 1 #=> True - -# Ein paar weitere Vergleiche -1 < 10 #=> True -1 > 10 #=> False -2 <= 2 #=> True -2 >= 2 #=> True - -# Vergleiche können verknüpft werden! -1 < 2 < 3 #=> True -2 < 3 < 2 #=> False - -# Strings werden mit " oder ' gebildet -"Das ist ein String." -'Das ist auch ein String.' - -# Strings können auch addiert werden! Vermeide dies aber lieber. -"Hallo " + "Welt!" #=> "Hallo Welt!" -# Strings können ohne "+" addiert werden -"Hallo " "welt!" # => "Hallo Welt!" - -# Ein String kann wie eine Liste von Zeichen verwendet werden -"Das ist ein String"[0] #=> 'D' - -# .format kann Strings formatieren -"{} können {} werden".format("Strings", "formatiert") - -# Schneller geht das mit Wiederholungen -"{0} mag Spagetthi, {0} liebt es zu Schwimmen und ganz besonders mag {0} {1}".format("Hans", "Blattsalat") -#=> "Hans mag Spagetthi, Hans liebt es zu Schwimmen und ganz besonders mag Hans Blattsalat" - -# Wir können Schlüsselwörter verwenden, wenn wir nicht abzählen wollen. -"{name} will {food} essen".format(name="Bob", food="Lasagne") -#=> "Bob will Lasagne kochen" - -#Falls dein Python 3 Code auch unter Python 2.5 oder darunter laufen soll, kann das alte Format benutzt werden: -"%s können %s werden" % ("Strings", "interpoliert") - - -# None ist ein Objekt -None #=> None - -# Verwendet nicht das Symbol für Gleichheit `==`, um Objekte mit None zu vergleichen -# Benutzt stattdessen `is`. Dieser Operator testet Objektidentität -"etc" is None #=> False -None is None #=> True - - - -# None, 0, und leere Strings/Listen werden alle als False bewertet. -# Alle anderen Werte sind True -bool(0) # => False -bool("") # => False -bool([]) #=> False -bool({}) #=> False - - -#################################################### -## 2. Variablen und Collections -#################################################### - -# Textausgabe ist sehr einfach -print("Ich bin Python. Schön, dich kennenzulernen!") - -# Es gibt keinen Grund, Variablen vor der Zuweisung zu deklarieren. -some_var = 5 # kleinschreibung_mit_unterstrichen entspricht der Norm -some_var #=> 5 - -# Das Ansprechen einer noch nicht deklarierten Variable löst eine Exception aus. -# Unter "Kontrollstruktur" kann noch mehr über -# Ausnahmebehandlung erfahren werden. -some_unknown_var # Löst einen NameError aus - -# Listen speichern Sequenzen -li = [] -# Wir können mit einer bereits gefüllten Liste anfangen -other_li = [4, 5, 6] - -# append fügt Daten am Ende der Liste ein -li.append(1) #li ist jetzt [1] -li.append(2) #li ist jetzt [1, 2] -li.append(4) #li ist jetzt [1, 2, 4] -li.append(3) #li ist jetzt [1, 2, 4, 3] -# Vom Ende der Liste mit pop entfernen -li.pop() #=> 3 und li ist jetzt [1, 2, 4] -# und dann wieder hinzufügen -li.append(3) # li ist jetzt wieder [1, 2, 4, 3]. - -# Greife auf Listen wie auf Arrays zu -li[0] #=> 1 -# Das letzte Element ansehen -li[-1] #=> 3 - -# Bei Zugriffen außerhalb der Liste kommt es jedoch zu einem IndexError -li[4] # Verursacht einen IndexError - -# Wir können uns Ranges mit Slice-Syntax ansehen -li[1:3] #=> [2, 4] -# Den Anfang auslassen -li[2:] #=> [4, 3] -# Das Ende auslassen -li[:3] #=> [1, 2, 4] -# Jeden Zweiten Eintrag auswählen -li[::2] # =>[1, 4] -# Eine umgekehrte Kopie zurückgeben -li[::-1] # => [3, 4, 2, 1] -# Jegliche Kombination dieser Syntax machen fortgeschrittene Slices möglich -# li[Start:Ende:Schritt] - -# Ein bestimmtes Element mit del aus der Liste entfernen -del li[2] # li ist jetzt [1, 2, 3] - -# Listen können addiert werden -li + other_li #=> [1, 2, 3, 4, 5, 6] - Hinweis: li und other_li werden in Ruhe gelassen - -# Listen mit extend verknüpfen -li.extend(other_li) # Jetzt ist li [1, 2, 3, 4, 5, 6] - -# Mit in auf Existenz eines Elements prüfen -1 in li #=> True - -# Die Länge der Liste mit len ermitteln -len(li) #=> 6 - - -# Tupel sind wie Listen, nur unveränderlich. -tup = (1, 2, 3) -tup[0] #=> 1 -tup[0] = 3 # Löst einen TypeError aus - -# Wir können all diese Listen-Dinge auch mit Tupeln anstellen -len(tup) #=> 3 -tup + (4, 5, 6) #=> (1, 2, 3, 4, 5, 6) -tup[:2] #=> (1, 2) -2 in tup #=> True - -# Wir können Tupel (oder Listen) in Variablen entpacken -a, b, c = (1, 2, 3) # a ist jetzt 1, b ist jetzt 2 und c ist jetzt 3 -# Tupel werden standardmäßig erstellt, wenn wir uns die Klammern sparen -d, e, f = 4, 5, 6 -# Es ist kinderleicht zwei Werte zu tauschen -e, d = d, e # d ist nun 5 und e ist nun 4 - - -# Dictionarys (Wörterbucher) speichern Schlüssel-Werte-Paare -empty_dict = {} -# Hier ein gefülltes Wörterbuch -filled_dict = {"one": 1, "two": 2, "three": 3} - -# Wir können Einträge mit [] nachschlagen -filled_dict["one"] #=> 1 - -# So holen wir alle Keys (Schlüssel) als Liste -list(filled_dict.keys()) #=> ["three", "two", "one"] -# Hinweis - Die Reihenfolge von Schlüsseln in der Liste ist nicht garantiert. -# Einzelne Resultate können anders angeordnet sein. - -# Alle Values (Werte) als Liste -list(filled_dict.values()) #=> [3, 2, 1] -# Hinweis - Hier gelten dieselben Einschränkungen für die Reihenfolge wie bei Schlüsseln. - -# Das Vorhandensein eines Schlüssels im Wörterbuch mit "in" prüfen -"one" in filled_dict #=> True -1 in filled_dict #=> False - -# Einen nicht vorhandenenen Schlüssel zu suchen, löst einen KeyError aus -filled_dict["four"] # KeyError - -# Mit der get-Methode verhindern wir das -filled_dict.get("one") #=> 1 -filled_dict.get("four") #=> None -# Die get-Methode unterstützt auch ein Standardargument, falls der Wert fehlt -filled_dict.get("one", 4) #=> 1 -filled_dict.get("four", 4) #=> 4 - -# Die setdefault-Methode ist ein sicherer Weg, ein neues Schlüssel-Wert-Paar anzulegen -filled_dict.setdefault("five", 5) #filled_dict["five"] wird auf 5 gesetzt -filled_dict.setdefault("five", 6) #filled_dict["five"] ist noch immer 5 - -# Einträge zu einem Wörterbuch hinzufügen -filled_dict.update({"four":4}) #=> {"one": 1, "two": 2, "three": 3, "four": 4} -#filled_dict["four"] = 4 # noch ein Weg, Werte hinzuzufügen - -# Schlüssel von einem Wörterbuch entfernen -del filled_dict["one"] # Entfert den Schlüssel "one" - - -# Sets speichern Mengen -empty_set = set() -# Initialisieren wir ein Set mit ein paar Werten -some_set = {1, 1, 2, 2, 3, 4} # some_set ist jetzt {1, 2, 3, 4} - -# Neue Variablen können einer Menge gleichgesetzt werden -filled_set = some_set - -# Mehr Elemente hinzufügen -filled_set.add(5) # filled_set ist jetzt {1, 2, 3, 4, 5} - -# Schnittmengen werden mit & gebildet -other_set = {3, 4, 5, 6} -filled_set & other_set #=> {3, 4, 5} - -# Mengen werden mit | vereinigt -filled_set | other_set #=> {1, 2, 3, 4, 5, 6} - -# Die Differenz einer Menge mit - bilden -{1,2,3,4} - {2,3,5} #=> {1, 4} - -# Auf Vorhandensein von Elementen mit in prüfen -2 in filled_set #=> True -10 in filled_set #=> False - - -#################################################### -## 3. Kontrollstruktur und Iteratoren -#################################################### - -# Erstellen wir mal eine Variable -some_var = 5 - -# Hier eine if-Anweisung. Die Einrückung ist in Python wichtig! -# gibt "some_var ist kleiner als 10" aus -if some_var > 10: - print("some_var ist viel größer als 10.") -elif some_var < 10: # Dieser elif-Absatz ist optional. - print("some_var ist kleiner als 10.") -else: # Das hier ist auch optional. - print("some_var ist tatsächlich 10.") - - -""" -For-Schleifen iterieren über Listen -Ausgabe: - hund ist ein Säugetier - katze ist ein Säugetier - maus ist ein Säugetier -""" -for animal in ["hund", "katze", "maus"]: - # Wir können Strings mit format() formatieren - print("{} ist ein Säugetier".format(animal)) - -""" -`range(Zahl)` gibt eine null-basierte Liste bis zur angegebenen Zahl wieder -Ausgabe: - 0 - 1 - 2 - 3 -""" -for i in range(4): - print(i) - -""" -"range(unten, oben)" gibt eine Liste von der unteren Zahl bis zur oberen Zahl aus -Ausgabe: - 4 - 5 - 6 - 7 -""" -for i in range(4, 8): - print(i) - -""" -While-Schleifen laufen, bis eine Bedingung erfüllt ist. -Ausgabe: - 0 - 1 - 2 - 3 -""" -x = 0 -while x < 4: - print(x) - x += 1 # Kurzform für x = x + 1 - -# Ausnahmebehandlung mit einem try/except-Block -try: - # Mit raise wird ein Fehler ausgegeben - raise IndexError("Das hier ist ein Index-Fehler") -except IndexError as e: - pass # Pass ist nur eine no-op. Normalerweise würden wir hier den Fehler klären. -except (TypeError, NameError): - pass # Mehrere Fehler können zusammen geklärt werden, falls erforderlich. -else: # Optional, hinter allen except-Blöcken - print("Keine Probleme!") # Wird nur ausgeführt, wenn keine Ausnahmen aufgetreten sind -finally: # Wird immer ausgeführt - print("Hier können wir Ressourcen aufräumen") - -# alternativ zu einem try/finally Block um Aufzuräumen: -with open("meineDatei.txt") as f: - for line in f: - print(line) - -# Python bietet ein fundamentales Konzept der Iteration. -# Das Objekt, auf das die Iteration, also die Wiederholung einer Methode angewandt wird heißt auf Englisch "iterable". -# Die range Methode gibt ein solches Objekt aus. - -filled_dict = {"one": 1, "two": 2, "three": 3} -our_iterable = filled_dict.keys() -print(our_iterable) #=> range(1,10). Dies ist ein "iterable" Objekt. - -# Über dieses können wir auch iterieren -for i in our_iterable: - print(i) # Gibt one, two, three aus - -# Allerdings können wir die einzelnen Elemente nicht mit ihrem index ausgeben -our_iterable[1] # TypeError - -# Ein iterable ist ein Objekt, das weiß wie es einen Iteratoren erschafft. -our_iterator = iter(our_iterable) - -# Unser Iterator ist ein Objekt, das sich merkt, welchen Status es gerade hat während wir durch es gehen. -# Das jeweils nächste Objekt bekommen wir mit "next()" -next(our_iterator) #=> "one" - -# Es hält den vorherigen Status -next(our_iterator) #=> "two" -next(our_iterator) #=> "three" - -# Nachdem alle Daten ausgegeben worden sind, kommt eine StopIterator Ausnahme zurück -next(our_iterator) # Gibt StopIteration aus - -# Alle Elemente können mit "list()" ausgegeben werden -list(filled_dict.keys()) #=> ["one", "two", "three"] - - - -#################################################### -## 4. Funktionen -#################################################### - -# Mit def neue Funktionen erstellen -def add(x, y): - print("x ist %s und y ist %s" % (x, y)) - return x + y # Werte werden mit return zurückgegeben - -# Funktionen mit Parametern aufrufen -add(5, 6) #=> Ausgabe ist "x ist 5 und y ist 6" und gibt 11 zurück - -# Ein anderer Weg des Funktionsaufrufs sind Schlüsselwort-Argumente -add(y=6, x=5) # Schlüsselwörter können in beliebiger Reihenfolge übergeben werden. - -# Wir können Funktionen mit beliebiger Anzahl von # Positionsargumenten definieren -def varargs(*args): - return args - -varargs(1, 2, 3) #=> (1,2,3) - - -# Wir können auch Funktionen mit beliebiger Anzahl -# Schlüsselwort-Argumenten definieren -def keyword_args(**kwargs): - return kwargs - -# Rufen wir es mal auf, um zu sehen, was passiert -keyword_args(big="foot", loch="ness") #=> {"big": "foot", "loch": "ness"} - -# Wir können beides gleichzeitig machen, wenn wir wollen -def all_the_args(*args, **kwargs): - print(args) - print(kwargs) -""" -all_the_args(1, 2, a=3, b=4) Ausgabe: - (1, 2) - {"a": 3, "b": 4} -""" - -# Beim Aufruf von Funktionen können wir das Gegenteil von varargs/kwargs machen! -# Wir benutzen dann *, um Tupel auszuweiten, und ** für kwargs. -args = (1, 2, 3, 4) -kwargs = {"a": 3, "b": 4} -all_the_args(*args) # äquivalent zu foo(1, 2, 3, 4) -all_the_args(**kwargs) # äquivalent zu foo(a=3, b=4) -all_the_args(*args, **kwargs) # äquivalent zu foo(1, 2, 3, 4, a=3, b=4) - - -# Anwendungsbereich von Funktionen -x = 5 - -def setX(num): - # lokale Variable x ist nicht die globale Variable x - x = num # => 43 - print (x) # => 43 - -def setGlobalX(num): - global x - print (x) # => 5 - x = num # globale Variable x ist jetzt 6 - print (x) # => 6 - -setX(43) -setGlobalX(6) - - -# Python hat First-Class-Funktionen -def create_adder(x): - def adder(y): - return x + y - return adder - -add_10 = create_adder(10) -add_10(3) #=> 13 - -# Es gibt auch anonyme Funktionen -(lambda x: x > 2)(3) #=> True - -# Es gibt auch Funktionen höherer Ordnung als Built-Ins -map(add_10, [1,2,3]) #=> [11, 12, 13] -filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7] - -# Wir können bei map- und filter-Funktionen auch List Comprehensions einsetzen -[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13] -[x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7] - -#################################################### -## 5. Klassen -#################################################### - -# Wir bilden die Unterklasse eines Objekts, um Klassen zu erhalten. -class Human(object): - - # Ein Klassenattribut. Es wird von allen Instanzen einer Klasse geteilt - species = "H. sapiens" - - # Ein simpler Konstruktor - def __init__(self, name): - # Wir weisen das Argument name dem name-Attribut der Instanz zu - self.name = name - - # Eine Instanzmethode. Alle Methoden erhalten self als erstes Argument. - def say(self, msg): - return "{name}: {message}".format(name=self.name, message=msg) - - # Eine Klassenmethode wird von allen Instanzen geteilt. - # Sie werden mit der aufrufenden Klasse als erstem Argument aufgerufen - @classmethod - def get_species(cls): - return cls.species - - # Eine statische Methode wird ohne Klasse oder Instanz aufgerufen - @staticmethod - def grunt(): - return "*grunt*" - - -# Eine Instanz einer Klasse erstellen -i = Human(name="Ian") -print(i.say("hi")) # gibt "Ian: hi" aus - -j = Human("Joel") -print(j.say("hello")) #gibt "Joel: hello" aus - -# Rufen wir mal unsere Klassenmethode auf -i.get_species() #=> "H. sapiens" - -# Ändern wir mal das gemeinsame Attribut -Human.species = "H. neanderthalensis" -i.get_species() #=> "H. neanderthalensis" -j.get_species() #=> "H. neanderthalensis" - -# Aufruf der statischen Methode -Human.grunt() #=> "*grunt*" - - -#################################################### -## 6. Module -#################################################### - -# Wir können Module importieren -import math -print(math.sqrt(16)) #=> 4.0 - -# Wir können auch nur spezielle Funktionen eines Moduls importieren -from math import ceil, floor -print(ceil(3.7)) #=> 4.0 -print(floor(3.7)) #=> 3.0 - -# Wir können auch alle Funktionen eines Moduls importieren -# Warnung: Dies wird nicht empfohlen -from math import * - -# Wir können Modulnamen abkürzen -import math as m -math.sqrt(16) == m.sqrt(16) #=> True - -# Module sind in Python nur gewöhnliche Dateien. Wir -# können unsere eigenen schreiben und importieren. Der Name des -# Moduls ist der Dateiname. - -# Wir können auch die Funktionen und Attribute eines -# Moduls herausfinden. -import math -dir(math) - - -#################################################### -## 7. Fortgeschritten -#################################################### - -# Generatoren helfen um Code schnell und einfach zu schreiben -def double_numbers(iterable): - for i in iterable: - yield i + i - -# Ein Generator erschafft Werte spontan -# Statt alle Werte auf einmal, wird bei jeder Iteration einer erschaffen. -# iteration. Das heißt, Werte größer als 15 werden nicht behandelt. -# Die range-Methode ist auch ein Generator. Im Fall einer Liste von 1-900000000 -# würde das sehr viel Zeit in Anspruch nehmen. -# Wenn wir eine variable mit einem Namen erschaffen wollen, das -# normalerweise mit einem Python - Schlüsselwort kollidieren würde, -# benutzen wir einen Unterstrich nach dem Wort. -range_ = range(1, 900000000) -# Alle Nummern bis zu einem Ergebnis von >=30 werden verdoppelt -for i in double_numbers(range_): - print(i) - if i >= 30: - break - - -# Dekoratoren -# In diesem Beispiel die Methode beg umwickelt say -# Beim Aufruf von beg, say wird aufgerufen -# Falls say_please true ist, ändert sich die ausgegebene Nachricht -from functools import wraps - - -def beg(target_function): - @wraps(target_function) - def wrapper(*args, **kwargs): - msg, say_please = target_function(*args, **kwargs) - if say_please: - return "{} {}".format(msg, "Please! I am poor :(") - return msg - - return wrapper - - -@beg -def say(say_please=False): - msg = "Can you buy me a beer?" - return msg, say_please - - -print(say()) # Can you buy me a beer? -print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( - -``` - -## Lust auf mehr? - -### Kostenlos online (Englisch) - -* [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) -* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) -* [Dive Into Python](http://www.diveintopython.net/) -* [Ideas for Python Projects](http://pythonpracticeprojects.com) -* [The Official Docs](http://docs.python.org/3/) -* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) -* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) -* [Python Course](http://www.python-course.eu/index.php) -* [First Steps With Python](https://realpython.com/learn/python-first-steps/) - -### Totholz (Englisch) - -* [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) -* [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) -* [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) diff --git a/de-de/pythonlegacy-de.html.markdown b/de-de/pythonlegacy-de.html.markdown new file mode 100644 index 00000000..d66a8551 --- /dev/null +++ b/de-de/pythonlegacy-de.html.markdown @@ -0,0 +1,766 @@ +--- +language: Python 2 (legacy) +contributors: + - ["Louie Dinh", "http://ldinh.ca"] +translators: + - ["kultprok", "http:/www.kulturproktologie.de"] +filename: learnpythonlegacy-de.py +lang: de-de +--- + +Anmerkungen des ursprünglichen Autors: +Python wurde in den frühen Neunzigern von Guido van Rossum entworfen. Es ist heute eine der beliebtesten Sprachen. Ich habe mich in Python wegen seiner syntaktischen Übersichtlichkeit verliebt. Eigentlich ist es ausführbarer Pseudocode. + +Feedback ist herzlich willkommen! Ihr erreicht mich unter [@louiedinh](http://twitter.com/louiedinh) oder louiedinh [at] [google's email service] + +Hinweis: Dieser Beitrag bezieht sich besonders auf Python 2.7, er sollte aber auf Python 2.x anwendbar sein. Haltet Ausschau nach einem Rundgang durch Python 3, der bald erscheinen soll. + +```python +# Einzeilige Kommentare beginnen mit einer Raute (Doppelkreuz) +""" Mehrzeilige Strings werden mit + drei '-Zeichen geschrieben und werden + oft als Kommentare genutzt. +""" + +#################################################### +## 1. Primitive Datentypen und Operatoren +#################################################### + +# Die Zahlen +3 #=> 3 + +# Mathematik funktioniert so, wie man das erwartet +1 + 1 #=> 2 +8 - 1 #=> 7 +10 * 2 #=> 20 +35 / 5 #=> 7 + +# Division ist ein wenig kniffliger. Ganze Zahlen werden ohne Rest dividiert +# und das Ergebnis wird automatisch abgerundet. +5 / 2 #=> 2 + +# Um das zu ändern, müssen wir Gleitkommazahlen einführen und benutzen +2.0 # Das ist eine Gleitkommazahl +11.0 / 4.0 #=> 2.75 Ahhh...schon besser + +# Rangfolge wird mit Klammern erzwungen +(1 + 3) * 2 #=> 8 + +# Boolesche Ausdrücke sind primitive Datentypen +True +False + +# Mit not wird negiert +not True #=> False +not False #=> True + +# Gleichheit ist == +1 == 1 #=> True +2 == 1 #=> False + +# Ungleichheit ist != +1 != 1 #=> False +2 != 1 #=> True + +# Ein paar weitere Vergleiche +1 < 10 #=> True +1 > 10 #=> False +2 <= 2 #=> True +2 >= 2 #=> True + +# Vergleiche können verknüpft werden! +1 < 2 < 3 #=> True +2 < 3 < 2 #=> False + +# Strings werden mit " oder ' gebildet +"Das ist ein String." +'Das ist auch ein String.' + +# Strings können addiert werden! +"Hello " + "world!" #=> "Hello world!" + +# Ein String kann wie eine Liste von Zeichen verwendet werden +"Das ist ein String"[0] #=> 'D' + +# Mit % können Strings formatiert werden, etwa so: +"%s können %s werden" % ("Strings", "interpoliert") + +# Ein modernerer Weg, um Strings zu formatieren, ist die format-Methode. +# Diese Methode wird bevorzugt +"{0} können {1} werden".format("Strings", "formatiert") +# Wir können Schlüsselwörter verwenden, wenn wir nicht abzählen wollen. +"{name} will {food} essen".format(name="Bob", food="Lasagne") + +# None ist ein Objekt +None #=> None + +# Verwendet nicht das Symbol für Gleichheit `==`, um Objekte mit None zu vergleichen +# Benutzt stattdessen `is` +"etc" is None #=> False +None is None #=> True + +# Der 'is'-Operator testet Objektidentität. Das ist nicht +# sehr nützlich, wenn wir mit primitiven Datentypen arbeiten, aber +# sehr nützlich bei Objekten. + +# None, 0, und leere Strings/Listen werden alle als False bewertet. +# Alle anderen Werte sind True +0 == False #=> True +"" == False #=> True + + +#################################################### +## 2. Variablen und Collections +#################################################### + +# Textausgabe ist sehr einfach +print "Ich bin Python. Schön, dich kennenzulernen!" + + +# Es gibt keinen Grund, Variablen vor der Zuweisung zu deklarieren. +some_var = 5 # kleinschreibung_mit_unterstrichen entspricht der Norm +some_var #=> 5 + +# Das Ansprechen einer noch nicht deklarierte Variable löst eine Exception aus. +# Unter "Kontrollstruktur" kann noch mehr über +# Ausnahmebehandlung erfahren werden. +some_other_var # Löst einen NameError aus + +# if kann als Ausdruck verwendet werden +"yahoo!" if 3 > 2 else 2 #=> "yahoo!" + +# Listen speichern Sequenzen +li = [] +# Wir können mit einer bereits gefüllten Liste anfangen +other_li = [4, 5, 6] + +# append fügt Daten am Ende der Liste ein +li.append(1) #li ist jetzt [1] +li.append(2) #li ist jetzt [1, 2] +li.append(4) #li ist jetzt [1, 2, 4] +li.append(3) #li ist jetzt [1, 2, 4, 3] +# Vom Ende der Liste mit pop entfernen +li.pop() #=> 3 und li ist jetzt [1, 2, 4] +# und dann wieder hinzufügen +li.append(3) # li ist jetzt wieder [1, 2, 4, 3]. + +# Greife auf Listen wie auf Arrays zu +li[0] #=> 1 +# Das letzte Element ansehen +li[-1] #=> 3 + +# Bei Zugriffen außerhalb der Liste kommt es jedoch zu einem IndexError +li[4] # Raises an IndexError + +# Wir können uns Ranges mit Slice-Syntax ansehen +li[1:3] #=> [2, 4] +# Den Anfang auslassen +li[2:] #=> [4, 3] +# Das Ende auslassen +li[:3] #=> [1, 2, 4] + +# Ein bestimmtes Element mit del aus der Liste entfernen +del li[2] # li ist jetzt [1, 2, 3] + +# Listen können addiert werden +li + other_li #=> [1, 2, 3, 4, 5, 6] - Hinweis: li und other_li werden in Ruhe gelassen + +# Listen mit extend verknüpfen +li.extend(other_li) # Jetzt ist li [1, 2, 3, 4, 5, 6] + +# Mit in auf Existenz eines Elements prüfen +1 in li #=> True + +# Die Länge der Liste mit len ermitteln +len(li) #=> 6 + + +# Tupel sind wie Listen, nur unveränderlich. +tup = (1, 2, 3) +tup[0] #=> 1 +tup[0] = 3 # Löst einen TypeError aus + +# Wir können all diese Listen-Dinge auch mit Tupeln anstellen +len(tup) #=> 3 +tup + (4, 5, 6) #=> (1, 2, 3, 4, 5, 6) +tup[:2] #=> (1, 2) +2 in tup #=> True + +# Wir können Tupel (oder Listen) in Variablen entpacken +a, b, c = (1, 2, 3) # a ist jetzt 1, b ist jetzt 2 und c ist jetzt 3 +# Tupel werden standardmäßig erstellt, wenn wir uns die Klammern sparen +d, e, f = 4, 5, 6 +# Es ist kinderleicht zwei Werte zu tauschen +e, d = d, e # d is now 5 and e is now 4 + + +# Dictionarys (Wörterbucher) speichern Key-Value-Paare +empty_dict = {} +# Hier ein gefülltes Wörterbuch +filled_dict = {"one": 1, "two": 2, "three": 3} + +# Wir können Einträge mit [] nachschlagen +filled_dict["one"] #=> 1 + +# So holen wir alle Keys (Schlüssel) als Liste +filled_dict.keys() #=> ["three", "two", "one"] +# Hinweis - Die Reihenfolge von Schlüsseln in der Liste ist nicht garantiert. +# Einzelne Resultate können anders angeordnet sein. + +# Alle Values (Werte) als Liste +filled_dict.values() #=> [3, 2, 1] +# Hinweis - Hier gelten dieselben Einschränkungen für die Reihenfolge wie bei Schlüsseln. + +# Das Vorhandensein eines Schlüssels im Wörterbuch mit in prüfen +"one" in filled_dict #=> True +1 in filled_dict #=> False + +# Einen nicht vorhandenenen Schlüssel zu suchen, löst einen KeyError aus +filled_dict["four"] # KeyError + +# Mit der get-Methode verhindern wir das +filled_dict.get("one") #=> 1 +filled_dict.get("four") #=> None +# Die get-Methode unterstützt auch ein Standardargument, falls der Wert fehlt +filled_dict.get("one", 4) #=> 1 +filled_dict.get("four", 4) #=> 4 + +# Die setdefault-Methode ist ein sicherer Weg, ein neues Schlüssel-Wert-Paar anzulegen +filled_dict.setdefault("five", 5) #filled_dict["five"] wird auf 5 gesetzt +filled_dict.setdefault("five", 6) #filled_dict["five"] ist noch immer 5 + + +# Sets speichern Mengen +empty_set = set() +# Initialisieren wir ein Set mit ein paar Werten +some_set = set([1,2,2,3,4]) # some_set ist jetzt set([1, 2, 3, 4]) + +# Seit Python 2.7 kann {} benutzt werden, um ein Set zu erstellen +filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4} + +# Mehr Elemente hinzufügen +filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} + +# Schnittmengen werden mit & gebildet +other_set = {3, 4, 5, 6} +filled_set & other_set #=> {3, 4, 5} + +# Mengen werden mit | vereinigt +filled_set | other_set #=> {1, 2, 3, 4, 5, 6} + +# Die Differenz einer Menge mit - bilden +{1,2,3,4} - {2,3,5} #=> {1, 4} + +# Auf Vorhandensein von Elementen mit in prüfen +2 in filled_set #=> True +10 in filled_set #=> False + + +#################################################### +## 3. Kontrollstruktur +#################################################### + +# Erstellen wir mal eine Variable +some_var = 5 + +# Hier eine if-Anweisung. Die Einrückung ist in Python wichtig! +# gibt "some_var ist kleiner als 10" aus +if some_var > 10: + print "some_var ist viel größer als 10." +elif some_var < 10: # Dieser elif-Absatz ist optional. + print "some_var ist kleiner als 10." +else: # Das hier ist auch optional. + print "some_var ist tatsächlich 10." + + +""" +For-Schleifen iterieren über Listen +Ausgabe: + hund ist ein Säugetier + katze ist ein Säugetier + maus ist ein Säugetier +""" +for animal in ["hund", "katze", "maus"]: + # Wir können Strings mit % formatieren + print "%s ist ein Säugetier" % animal + +""" +`range(Zahl)` gibt eine null-basierte Liste bis zur angegebenen Zahl wieder +Ausgabe: + 0 + 1 + 2 + 3 +""" +for i in range(4): + print i + +""" +While-Schleifen laufen, bis eine Bedingung erfüllt ist. +Ausgabe: + 0 + 1 + 2 + 3 +""" +x = 0 +while x < 4: + print x + x += 1 # Kurzform für x = x + 1 + +# Ausnahmebehandlung mit einem try/except-Block + +# Funktioniert in Python 2.6 und höher: +try: + # Mit raise wird ein Fehler ausgegeben + raise IndexError("Das hier ist ein Index-Fehler") +except IndexError as e: + pass # Pass ist nur eine no-op. Normalerweise würden wir hier den Fehler klären. + + +#################################################### +## 4. Funktionen +#################################################### + +# Mit def neue Funktionen erstellen +def add(x, y): + print "x ist %s und y ist %s" % (x, y) + return x + y # Werte werden mit return zurückgegeben + +# Funktionen mit Parametern aufrufen +add(5, 6) #=> Ausgabe ist "x ist 5 und y ist 6" und gibt 11 zurück + +# Ein anderer Weg des Funktionsaufrufs sind Schlüsselwort-Argumente +add(y=6, x=5) # Schlüsselwörter können in beliebiger Reihenfolge übergeben werden. + +# Wir können Funktionen mit beliebiger Anzahl von # Positionsargumenten definieren +def varargs(*args): + return args + +varargs(1, 2, 3) #=> (1,2,3) + + +# Wir können auch Funktionen mit beliebiger Anzahl +# Schlüsselwort-Argumenten definieren +def keyword_args(**kwargs): + return kwargs + +# Rufen wir es mal auf, um zu sehen, was passiert +keyword_args(big="foot", loch="ness") #=> {"big": "foot", "loch": "ness"} + +# Wir können beides gleichzeitig machem, wenn wir wollen +def all_the_args(*args, **kwargs): + print args + print kwargs +""" +all_the_args(1, 2, a=3, b=4) Ausgabe: + (1, 2) + {"a": 3, "b": 4} +""" + +# Beim Aufruf von Funktionen können wir das Gegenteil von varargs/kwargs machen! +# Wir benutzen dann *, um Tupel auszuweiten, und ** für kwargs. +args = (1, 2, 3, 4) +kwargs = {"a": 3, "b": 4} +all_the_args(*args) # äquivalent zu foo(1, 2, 3, 4) +all_the_args(**kwargs) # äquivalent zu foo(a=3, b=4) +all_the_args(*args, **kwargs) # äquivalent zu foo(1, 2, 3, 4, a=3, b=4) + +# Python hat First-Class-Funktionen +def create_adder(x): + def adder(y): + return x + y + return adder + +add_10 = create_adder(10) +add_10(3) #=> 13 + +# Es gibt auch anonyme Funktionen +(lambda x: x > 2)(3) #=> True + +# Es gibt auch Funktionen höherer Ordnung als Built-Ins +map(add_10, [1,2,3]) #=> [11, 12, 13] +filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7] + +# Wir können bei map- und filter-Funktionen auch List Comprehensions einsetzen +[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13] +[x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7] + + +#################################################### +## 5. Module +#################################################### + +# Wir können Module importieren +import math +print math.sqrt(16) #=> 4.0 + +# Wir können auch nur spezielle Funktionen eines Moduls importieren +from math import ceil, floor +print ceil(3.7) #=> 4.0 +print floor(3.7) #=> 3.0 + +# Wir können auch alle Funktionen eines Moduls importieren +# Warnung: Dies wird nicht empfohlen +from math import * + +# Wir können Modulnamen abkürzen +import math as m +math.sqrt(16) == m.sqrt(16) #=> True + +# Module sind in Python nur gewöhnliche Dateien. Wir +# können unsere eigenen schreiben und importieren. Der Name des +# Moduls ist der Dateiname. + +# Wir können herausfinden, welche Funktionen und Attribute in einem +# Modul definiert sind. +import math +dir(math) + +# Wenn Sie ein Python-Skript namens math.py im selben Ordner +# wie Ihr aktuelles Skript haben, wird die Datei math.py +# anstelle des integrierten Python-Moduls geladen. +# Dies geschieht, weil der lokale Ordner Vorrang +# vor den in Python integrierten Bibliotheken hat. + + +#################################################### +## 6. Klassen +#################################################### + +# Wir verwenden das Schlüsselwort "class" um eine Klasse zu erzeugen. +class Human(object): + + # Ein Klassenattribut. Es wird von allen Instanzen einer Klasse geteilt + species = "H. sapiens" + + # Ein simpler Konstruktor, wird aufgerufen, wenn diese Klasse instanziiert wird. + # Beachten Sie, dass die doppelten vorangestellten und nachgestellten + # Unterstriche Objekte oder Attribute bezeichnen, die von Python verwendet werden, + # aber in benutzergesteuerten Namespaces leben. + # Methoden (oder Objekte oder Attribute) wie: __init__, __str__, __repr__ usw. + # werden als Sondermethoden (oder manchmal als Dundermethoden bezeichnet) bezeichnet. + # Sie sollten solche Namen nicht selbst erfinden. + def __init__(self, name): + # Wir weisen das Argument name dem name-Attribut der Instanz zu + self.name = name + + # Eine Instanzmethode. Alle Methoden erhalten "self" als erstes Argument. + def say(self, msg): + return "%s: %s" % (self.name, msg) + + # Eine weitere Instanzmethode + def sing(self): + return 'yo... yo... microphone check... one two... one two...' + + # Eine Klassenmethode wird von allen Instanzen geteilt. + # Sie werden mit der aufrufenden Klasse als erstem Argument aufgerufen + @classmethod + def get_species(cls): + return cls.species + + # Eine statische Methode wird ohne Klasse oder Instanz aufgerufen + @staticmethod + def grunt(): + return "*grunt*" + + # Eine Eigenschaft (Property) ist wie ein Getter. + # Es verwandelt die Methode age() in ein schreibgeschütztes Attribut mit demselben Namen. + # Es ist jedoch nicht nötig, triviale Getter und Setter in Python zu schreiben. + @property + def age(self): + return self._age + + # Damit kann die Eigenschaft festgelegt werden + @age.setter + def age(self, age): + self._age = age + + # Damit kann die Eigenschaft gelöscht werden + @age.deleter + def age(self): + del self._age + +# Wenn ein Python-Interpreter eine Quelldatei liest, führt er den gesamten Code aus. +# Diese __name__-Prüfung stellt sicher, dass dieser Codeblock nur ausgeführt wird, +# wenn dieses Modul das Hauptprogramm ist. +if __name__ == '__main__': + # Eine Instanz einer Klasse erstellen + i = Human(name="Ian") + i.say("hi") # "Ian: hi" + j = Human("Joel") + j.say("hello") # "Joel: hello" + # i und j sind Instanzen des Typs Mensch, oder anders ausgedrückt: Sie sind Objekte des Menschen + + # Rufen wir unsere Klassenmethode auf + i.say(i.get_species()) # "Ian: H. sapiens" + + # Ändern wir das gemeinsame Attribut + Human.species = "H. neanderthalensis" + i.say(i.get_species()) # => "Ian: H. neanderthalensis" + j.say(j.get_species()) # => "Joel: H. neanderthalensis" + + # Aufruf der statischen Methode + print(Human.grunt()) # => "*grunt*" + + # Kann keine statische Methode mit Instanz des Objekts aufrufen, + # da i.grunt () automatisch "self" (das Objekt i) als Argument verwendet + print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given + + # Die Eigenschaft für diese Instanz aktualisieren + i.age = 42 + # die Eigenschaft auslesen + i.say(i.age) # => "Ian: 42" + j.say(j.age) # => "Joel: 0" + # die Eigenschaft löschen + del i.age + # i.age # => würde einen AttributeError werfen + +#################################################### +## 6.1 Inheritance +#################################################### + +# Vererbung ermöglicht die Definition neuer untergeordneter Klassen, +# die Methoden und Variablen von ihrer übergeordneten Klasse erben. + +# Wenn Sie die oben definierte Human-Klasse als Basis- oder Elternklasse verwenden, +# können Sie eine untergeordnete Klasse, Superhero, definieren, die die Klassenvariablen +# wie "species", "name" und "age" sowie Methoden wie "sing" und "grunzen" aus der Klasse Human erbt. +# Die Untergeordnete Klasse kann aber auch eigene Eigenschaften haben. + +# Um von der Modularisierung per Datei zu profitieren, können Sie die Klassen +# in ihren eigenen Dateien platzieren, z. B. human.py + +# Um Funktionen aus anderen Dateien zu importieren, verwenden Sie das folgende Format +# from "Dateiname-ohne-Erweiterung" impotr "Funktion-oder-Klasse" + +from human import Human + +# Geben Sie die übergeordnete(n) Klasse(n) als Parameter für die Klassendefinition an +class Superhero(Human): + + # Wenn die untergeordnete Klasse alle Definitionen des übergeordneten Elements + # ohne Änderungen erben soll, können Sie einfach das Schlüsselwort "pass" + # (und nichts anderes) verwenden. In diesem Fall wird jedoch auskommentiert, + # um eine eindeutige untergeordnete Klasse zuzulassen: + # pass + + # Kindklassen können die Attribute ihrer Eltern überschreiben + species = 'Superhuman' + + # Kinder erben automatisch den Konstruktor ihrer übergeordneten Klasse + # einschließlich ihrer Argumente, können aber auch zusätzliche Argumente oder + # Definitionen definieren und ihre Methoden zB den Klassenkonstruktor überschreiben. + # Dieser Konstruktor erbt das Argument "name" von der Klasse "Human" und + # fügt die Argumente "superpowers" und "movie" hinzu: + def __init__(self, name, movie=False, + superpowers=["super strength", "bulletproofing"]): + + # zusätzliche Klassenattribute hinzufügen: + self.fictional = True + self.movie = movie + # Beachten Sie die veränderlichen Standardwerte, da die Standardwerte gemeinsam genutzt werden + self.superpowers = superpowers + + # Mit der Funktion "super" können Sie auf die Methoden der übergeordneten Klasse + # zugreifen, die vom untergeordneten Objekt überschrieben werden, + # in diesem Fall die Methode __init__. + # Dies ruft den Konstruktor der übergeordneten Klasse auf: + super().__init__(name) + + # überschreiben der "sing" Methode + def sing(self): + return 'Dun, dun, DUN!' + + # eine zusätzliche Instanzmethode hinzufügen + def boast(self): + for power in self.superpowers: + print("I wield the power of {pow}!".format(pow=power)) + +if __name__ == '__main__': + sup = Superhero(name="Tick") + + # Instanztypprüfungen + if isinstance(sup, Human): + print('I am human') + if type(sup) is Superhero: + print('I am a superhero') + + # Die Reihenfolge der Methodenauflösung (MRO = Method Resolution Order) anzeigen, die sowohl von getattr() als auch von super() verwendet wird. + # Dieses Attribut ist dynamisch und kann aktualisiert werden. + print(Superhero.__mro__) # => (<class '__main__.Superhero'>, + # => <class 'human.Human'>, <class 'object'>) + + # Ruft die übergeordnete Methode auf, verwendet jedoch das eigene Klassenattribut + print(sup.get_species()) # => Superhuman + + # Ruft die überschriebene Methode auf + print(sup.sing()) # => Dun, dun, DUN! + + # Ruft die Methode von Human auf + sup.say('Spoon') # => Tick: Spoon + + # Aufruf einer Methode, die nur in Superhero existiert + sup.boast() # => I wield the power of super strength! + # => I wield the power of bulletproofing! + + # Vererbtes Klassenattribut + sup.age = 31 + print(sup.age) # => 31 + + # Attribut, das nur in Superhero existiert + print('Am I Oscar eligible? ' + str(sup.movie)) + +#################################################### +## 6.2 Multiple Inheritance +#################################################### + +# Eine weitere Klassendefinition +# bat.py + +class Bat: + + species = 'Baty' + + def __init__(self, can_fly=True): + self.fly = can_fly + + # This class also has a say method + def say(self, msg): + msg = '... ... ...' + return msg + + # And its own method as well + def sonar(self): + return '))) ... (((' + +if __name__ == '__main__': + b = Bat() + print(b.say('hello')) + print(b.fly) + +# Und noch eine andere Klassendefinition, die von Superhero und Bat erbt +# superhero.py +from superhero import Superhero +from bat import Bat + +# Definieren Sie Batman als eine Kindklasse, das von Superheld und Bat erbt +class Batman(Superhero, Bat): + + def __init__(self, *args, **kwargs): + # In der Regel müssen Sie super aufrufen, um Attribute zu erben: + # super (Batman, selbst) .__ init__ (* args, ** kwargs) + # Allerdings handelt es sich hier um Mehrfachvererbung, und super() + # funktioniert nur mit der nächsten Basisklasse in der MRO-Liste. + # Stattdessen rufen wir explizit __init__ für alle Vorfahren auf. + # Die Verwendung von *args und **kwargs ermöglicht die saubere Übergabe von + # Argumenten, wobei jedes übergeordnete Element eine Schicht der Zwiebel "abschält". + Superhero.__init__(self, 'anonymous', movie=True, + superpowers=['Wealthy'], *args, **kwargs) + Bat.__init__(self, *args, can_fly=False, **kwargs) + # überschreibt den Wert für das Namensattribut + self.name = 'Sad Affleck' + + def sing(self): + return 'nan nan nan nan nan batman!' + +if __name__ == '__main__': + sup = Batman() + + # Die Reihenfolge der Methodenauflösung (MRO = Method Resolution Order) anzeigen, + # die sowohl von getattr() als auch von super() verwendet wird. + # Dieses Attribut ist dynamisch und kann aktualisiert werden. + print(Batman.__mro__) # => (<class '__main__.Batman'>, + # => <class 'superhero.Superhero'>, + # => <class 'human.Human'>, + # => <class 'bat.Bat'>, <class 'object'>) + + # Ruft die übergeordnete Methode auf, verwendet jedoch das eigene Klassenattribut + print(sup.get_species()) # => Superhuman + + # Ruft die überschriebene Methode auf + print(sup.sing()) # => nan nan nan nan nan batman! + + # Ruft die Methode von Human auf, weil die Reihenfolge der Vererbung wichtig ist + sup.say('I agree') # => Sad Affleck: I agree + + # Aufrufmethode, die nur im 2. Vorfahren existiert + print(sup.sonar()) # => ))) ... ((( + + # Vererbtes Klassenattribut + sup.age = 100 + print(sup.age) # => 100 + + # Vererbtes Attribut vom 2. Vorfahren, dessen Standardwert überschrieben wurde. + print('Can I fly? ' + str(sup.fly)) # => Can I fly? False + + +#################################################### +## 7. Fortgeschrittenes +#################################################### + +# Generatoren helfen Ihnen, lazy Code zu erstellen. +def double_numbers(iterable): + for i in iterable: + yield i + i + +# Generatoren sind speichereffizient, da sie nur die Daten laden, +# die zur Verarbeitung des nächsten Werts in der iterierbaren Komponente +# erforderlich sind. Dadurch können sie ansonsten unzulässig große Wertebereiche ausführen. +# HINWEIS: `range` ersetzt` xrange` in Python 3. +for i in double_numbers(range(1, 900000000)): # `range` ist ein Generator. + print(i) + if i >= 30: + break + +# Genauso wie Sie ein 'list comprehension' (Listen Abstraktion) erstellen können, können Sie auch 'generator comprehension' (Generator Abstraktion) erstellen. +values = (-x for x in [1,2,3,4,5]) +for x in values: + print(x) # prints -1 -2 -3 -4 -5 to console/terminal + +# Sie können eine Generator Abstraktion auch direkt in eine Liste umwandeln (casten). +values = (-x for x in [1,2,3,4,5]) +gen_to_list = list(values) +print(gen_to_list) # => [-1, -2, -3, -4, -5] + +# Decorators +# In diesem Beispiel umschliesst "beg" "say". Wenn say_please True ist, wird die zurückgegebene Nachricht geändert. +from functools import wraps + +def beg(target_function): + @wraps(target_function) + def wrapper(*args, **kwargs): + msg, say_please = target_function(*args, **kwargs) + if say_please: + return "{} {}".format(msg, "Please! I am poor :(") + return msg + + return wrapper + +@beg +def say(say_please=False): + msg = "Can you buy me a beer?" + return msg, say_please + + +print(say()) # Can you buy me a beer? +print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( + +``` + +## Lust auf mehr? + +### Kostenlos online (Englisch) + +* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) +* [Dive Into Python](http://www.diveintopython.net/) +* [The Official Docs](http://docs.python.org/2.6/) +* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) +* [Python Module of the Week](http://pymotw.com/2/) + +### Totholz (Englisch) + +* [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) +* [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) +* [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) + diff --git a/de-de/yaml-de.html.markdown b/de-de/yaml-de.html.markdown index d0e3471a..0332c912 100644 --- a/de-de/yaml-de.html.markdown +++ b/de-de/yaml-de.html.markdown @@ -1,7 +1,7 @@ --- language: yaml contributors: - - ["Adam Brenecki", "https://github.com/adambrenecki"] + - ["Leigh Brenecki", "https://github.com/adambrenecki"] translators: - ["Ruben M.", "https://github.com/switchhax"] filename: learnyaml-de.yaml @@ -111,7 +111,7 @@ python_komplexe_Zahlen: !!python/komplex 1+2j # EXTRA YAML TYPEN # #################### -# Strings and Zahlen sind nicht die einzigen Skalare, welche YAML versteht. +# Strings und Zahlen sind nicht die einzigen Skalare, welche YAML versteht. # ISO-formatierte Datumsangaben and Zeiangaben können ebenso geparsed werden. DatumZeit: 2001-12-15T02:59:43.1Z DatumZeit_mit_Leerzeichen: 2001-12-14 21:59:43.10 -5 |