mirror of
https://gitlab.rlp.net/pgp/pgp1-python-einfuehrung
synced 2024-11-16 13:48:11 +00:00
Worked over some of the texts. Added some more information about functions.
This commit is contained in:
parent
de7125acec
commit
5f235de550
1 changed files with 274 additions and 63 deletions
|
@ -8,7 +8,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"In unserer heutigen digitalen Welt sind Computer nicht mehr aus unserem Alltag wegzudenken. Ob in der Finanzwelt, Industrie aber auch in der Wissenschaft erledigen Computer in Sekundenschnelle komplizierte Rechnungen und helfen dem Anwender komplizierte Sachverhalte vereinfacht wieder zu geben. Daher empfiehlt es sich insbesondere als Physiker zumindest die Grundlagen einer beliebigen Programmiersprache zu beherrschen. \n",
|
"In unserer heutigen digitalen Welt sind Computer nicht mehr aus unserem Alltag wegzudenken. Ob in der Finanzwelt, Industrie aber auch in der Wissenschaft erledigen Computer in Sekundenschnelle komplizierte Rechnungen und helfen dem Anwender komplizierte Sachverhalte vereinfacht wieder zu geben. Daher empfiehlt es sich insbesondere als Physiker zumindest die Grundlagen einer beliebigen Programmiersprache zu beherrschen. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Im folgenden werden wir uns gemeinsam die Grundzüge der Programmiersprache **Python** erarbeiten. Ein besonderes Augenmerk liegt hierbei auf den verschiedenen Herausforderungen die das analysieren von Experimentdaten mit sich bringt. Um euch bestens auf die Anforderungen im **physikalische Grundpraktikum (PGP)** vorzubereiten lernen wir im Folgenden wie man:\n",
|
"Im folgenden werden wir uns gemeinsam die Grundzüge der Programmiersprache **Python** erarbeiten. Ein besonderes Augenmerk liegt hierbei auf den verschiedenen Herausforderungen die das analysieren von experimentellen Daten mit sich bringt. Um Sie bestens auf die Anforderungen im **physikalische Grundpraktikum (PGP)** vorzubereiten lernen wir im Folgenden wie man:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* einfache Rechnungen mit Python durchführt\n",
|
"* einfache Rechnungen mit Python durchführt\n",
|
||||||
"* \"Mathematische\" Funktionen definiert\n",
|
"* \"Mathematische\" Funktionen definiert\n",
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
"* Daten in Form von Graphen richtig darstellt\n",
|
"* Daten in Form von Graphen richtig darstellt\n",
|
||||||
"* eine Ausgleichsgerade von Datenpunkten berechnen kann.\n",
|
"* eine Ausgleichsgerade von Datenpunkten berechnen kann.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Damit ihr das neu gelernte Wissen direkt vertiefen könnt, wird dieses Notebook an verschiedenen Stellen kleinere Aufgaben für euch bereit halten."
|
"Damit Sie das neu erlernte Wissen direkt vertiefen können, wird dieses Notebook an verschiedenen Stellen kleinere Aufgaben für Sie bereit halten. Die Aufgaben sind durch orangefarbene Boxen hervorgehoben. Es gilt alle Aufgaben zu bearbeiten! "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,16 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## Jupyter Notebooks ausführen\n",
|
"## Jupyter Notebooks ausführen\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
"### ZDV Jupyter Hub\n",
|
||||||
|
"\n",
|
||||||
|
"Sie können auch den durch die ZDV angebotenen Jupyter Hub (https://jupyterhub.zdv.uni-mainz.de/hub/login) zur Bearbeitung Ihrer Notebooks verwenden. **Falls Sie das Jupyterhub von außerhalb des Uni-Netzwerks erreichen wollen, müssen Sie eine VPN-Verbindung zum Uni-Netzwerk aufbauen.** Eine Anleitung für die gebräuchlichsten Betriebssysteme finden Sie [hier]( https://www.zdv.uni-mainz.de/vpn-netz-zugang-von-ausserhalb-des-campus/). \n",
|
||||||
|
"\n",
|
||||||
|
"Um Zugang zum Jupyter-Hub zu erhalten, müssen Sie sich zunächst mit Ihrem Uni-Account anmelden. Danach erscheint eine Auswahlseite, auf der Sie die Art der Jupyter Umgebung auswählen. Für das Praktikum ist die Standardumgebung die richtige Wahl, s. Bild unten.\n",
|
||||||
|
"\n",
|
||||||
|
"![images/Screenshot_ZDV_JupyterHub.png](attachment:Screenshot_ZDV_JupyterHub.png)\n",
|
||||||
|
"\n",
|
||||||
|
"Klicken Sie auf die Schaltfläche **Spawn**, dann öffnet sich, wie bei der lokalen Installation, das Notebook Dashboard.\n",
|
||||||
|
"\n",
|
||||||
"### Lokale Installation\n",
|
"### Lokale Installation\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Falls Sie das Jupyter Notebook auf Ihrem Computer installiert haben, sind Sie bereit, den Notebook-Server zu betreiben. Sie können den Notebook-Server über die Befehlszeile (mit Terminal unter Mac/Linux, Eingabeaufforderung unter Windows) starten, indem Sie ihn ausführen:\n",
|
"Falls Sie das Jupyter Notebook auf Ihrem Computer installiert haben, sind Sie bereit, den Notebook-Server zu betreiben. Sie können den Notebook-Server über die Befehlszeile (mit Terminal unter Mac/Linux, Eingabeaufforderung unter Windows) starten, indem Sie ihn ausführen:\n",
|
||||||
|
@ -40,18 +50,9 @@
|
||||||
"\n",
|
"\n",
|
||||||
"Wenn sich das Notebook in Ihrem Browser öffnet, sehen Sie das Notebook Dashboard, das eine Liste der Notebooks, Dateien und Unterverzeichnisse in dem Verzeichnis anzeigt, in dem der Notebook-Server gestartet wurde. Meistens werden Sie einen Notebook-Server im obersten Verzeichnis mit Notebooks starten wollen. Oftmals wird dies Ihr Home-Verzeichnis sein.\n",
|
"Wenn sich das Notebook in Ihrem Browser öffnet, sehen Sie das Notebook Dashboard, das eine Liste der Notebooks, Dateien und Unterverzeichnisse in dem Verzeichnis anzeigt, in dem der Notebook-Server gestartet wurde. Meistens werden Sie einen Notebook-Server im obersten Verzeichnis mit Notebooks starten wollen. Oftmals wird dies Ihr Home-Verzeichnis sein.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"### ZDV Jupyter Hub\n",
|
|
||||||
"\n",
|
|
||||||
"Sie können auch den durch die ZDV angebotenen Jupyter Hub (https://jupyterhub.zdv.uni-mainz.de/hub/login) zur Bearbeitung Ihrer Notebooks verwenden. Falls Sie das Jupyterhub von außerhalb des Uni-Netzwerks erreichen wollen, müssen Sie eine VPN-Verbindung zum Uni-Netzwerk aufbauen. Eine Anleitung für die gebräuchlichsten Betriebssysteme finden Sie hier: https://www.zdv.uni-mainz.de/vpn-netz-zugang-von-ausserhalb-des-campus/.Hier müssen Sie sich zunächst mit Ihrem Uni-Account anmelden. Danach erscheint eine Auswahlseite, auf der Sie die Art der Jupyter Umgebung auswählen. Für das Praktikum ist die Standardumgebung die richtige Wahl, s. Bild unten.\n",
|
|
||||||
"\n",
|
|
||||||
"![images/Screenshot_ZDV_JupyterHub.png](attachment:Screenshot_ZDV_JupyterHub.png)\n",
|
|
||||||
"\n",
|
|
||||||
"Klicken Sie auf die Schaltfläche **Spawn**, dann öffnet sich, wie bei der lokalen Installation, das Notebook Dashboard.\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"## Ein neues Notebook-Dokument anlegen\n",
|
"## Ein neues Notebook-Dokument anlegen\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Ein neues Notebook kann jederzeit erstellt werden, entweder über das Dashboard oder über die Menüoption Datei ‣ Neu aus einem aktiven Notebook heraus. Das neue Notebook wird im selben Verzeichnis erstellt und öffnet sich in einem neuen Browser-Tab. Es wird auch als neuer Eintrag in der Notebookliste auf dem Dashboard angezeigt.\n",
|
"Ein neues Notebook kann jederzeit erstellt werden, entweder über das Dashboard oder über die Menüoption File ‣ Neu aus einem aktiven Notebook heraus. Das neue Notebook wird im selben Verzeichnis erstellt und öffnet sich in einem neuen Browser-Tab. Es wird auch als neuer Eintrag in der Notebookliste auf dem Dashboard angezeigt.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"![](https://jupyter-notebook.readthedocs.io/en/latest/_images/new-notebook.gif)\n",
|
"![](https://jupyter-notebook.readthedocs.io/en/latest/_images/new-notebook.gif)\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -108,7 +109,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"Sie können den Berechnungsprozess versiert dokumentieren, indem Sie beschreibenden Text mit Code abwechseln und Rich Text verwenden. In IPython wird dies durch die Markierung von Text mit der Markdown-Sprache erreicht. Die entsprechenden Zellen werden als Markdown-Zellen bezeichnet. Die Markdown-Sprache bietet eine einfache Möglichkeit, dieses Textmarkup durchzuführen, d.h. festzulegen, welche Teile des Textes hervorgehoben werden sollen (Kursivschrift), Fett, Formularlisten usw.\n",
|
"Sie können den Berechnungsprozess versiert dokumentieren, indem Sie beschreibenden Text mit Code abwechseln und Rich Text verwenden. In IPython wird dies durch die Markierung von Text mit der Markdown-Sprache erreicht. Die entsprechenden Zellen werden als Markdown-Zellen bezeichnet. Die Markdown-Sprache bietet eine einfache Möglichkeit, dieses Textmarkup durchzuführen, d.h. festzulegen, welche Teile des Textes hervorgehoben werden sollen (Kursivschrift), Fett, Formularlisten usw.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Innerhalb von Markdown-Zellen können Sie mathematische Ausdrücke auch auf einfache Weise mit der Standard-LaTeX-Notation einbinden: $...$ für Inline-Mathematik und $$...$$ für angezeigte Mathematik. Wenn die Markdown-Zelle ausgeführt wird, werden die LaTeX-Abschnitte automatisch in der HTML-Ausgabe als Gleichungen mit hochwertiger Typografie dargestellt. Möglich wird dies durch MathJax, das eine große Teilmenge der LaTeX-Funktionalität unterstützt.\n",
|
"Innerhalb von Markdown-Zellen können Sie mathematische Ausdrücke auch auf einfache Weise mit der Standard-LaTeX-Notation einbinden: `$...$` für Inline-Mathematik und `$$...$$` für angezeigte Mathematik. Wenn die Markdown-Zelle ausgeführt wird, werden die LaTeX-Abschnitte automatisch in der HTML-Ausgabe als Gleichungen mit hochwertiger Typografie dargestellt. Möglich wird dies durch MathJax, das eine große Teilmenge der LaTeX-Funktionalität unterstützt. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Es existiert also eine ganze Bandbreite an Formatierungsmöglichkeiten. Hier einige Beispiele:\n",
|
"Es existiert also eine ganze Bandbreite an Formatierungsmöglichkeiten. Hier einige Beispiele:\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -146,7 +147,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"$ f(x) = \\int\\limits_0^\\infty e^{-x} \\, dx $\n",
|
"$ f(x) = \\int\\limits_0^\\infty e^{-x} \\, dx $\n",
|
||||||
"\n",
|
"\n",
|
||||||
"(Latex werdet ihr beim F-Praktikum kennen lernen)\n",
|
"(Latex werdet Sie verstärkt im F-Praktikum kennen lernen)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Bilder:**\n",
|
"**Bilder:**\n",
|
||||||
|
@ -182,31 +183,31 @@
|
||||||
"\n",
|
"\n",
|
||||||
"Im folgenden wollen wir erst einmal mit den Grundlagen des Notebooks vertraut machen. Insbesondere wollen wir lernen, wie wir eine Markdown- und eine Code-Zelle erstellen, bearbeiten und ausführen. \n",
|
"Im folgenden wollen wir erst einmal mit den Grundlagen des Notebooks vertraut machen. Insbesondere wollen wir lernen, wie wir eine Markdown- und eine Code-Zelle erstellen, bearbeiten und ausführen. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"* Erstellt zunächst eine Code-Zelle unterhalb dieser und berechnet die Summe zweier beliebiger ganzer Zahlen. Geht dabei wie folgt vor:\n",
|
"* Erstellt zunächst eine Code-Zelle unterhalb dieser Aufgaben Zelle und berechnen Sie die Summe zweier beliebiger ganzer Zahlen. Gehen Sie dabei wie folgt vor:\n",
|
||||||
" 1. Klickt die Zelle dieser Aufgabe an, so dass sie eine blaue Umrandung bekommt (je nach Bildschirmauflösung könnt ihr nur links einen blauen Balken erkennen). Ihr befindet euch nun im so genannten \"Command Modus\". In diesem Modus könnt ihr mit den Pfeiltasten eurer Tastatur durch das Notebook navigieren oder die Struktur des Notebooks bzw. seiner Zellen mit Hilfe von Tasten/Tastenkombinationen modifizieren.\n",
|
" 1. Klicken Sie die Zelle dieser Aufgabe an, so dass die Zelle eine blaue Umrandung bekommt (je nach Bildschirmauflösung könnt Sie nur links einen blauen Balken erkennen). Sie befinden sich nun im so genannten \"Command Modus\". In diesem Modus könnt Sie mit Hilfe der Pfeiltasten durch das Notebook navigieren oder die Struktur des Notebooks bzw. seiner Zellen mit Hilfe von Tasten/Tastenkombinationen modifizieren.\n",
|
||||||
" 2. Benutzt nun die Taste **B** um eine Code-Zelle unterhalb (**B**elow) dieser Zelle zu erstellen. Ihr werdet feststellen, das euer Navigator direkt zu der neu erstellten Zelle springt (blaue Umrandung).\n",
|
" 2. Benutzen Sie nun die Taste **B** um eine Code-Zelle unterhalb (**B**elow) dieser Zelle zu erstellen. Sie werden feststellen, dass Ihr Navigator direkt zu der neu erstellten Zelle springt (blaue Umrandung).\n",
|
||||||
" 3. Um nun diese neu erstellte Code-Zelle zu editieren, klickt ihr diese mit dem Mauszeiger an. Eure Zellenumrandung sollte von Blau auf Grün wechseln. Dies zeigt an, dass ihr euch nun im Editiermodus für diese Zelle befindet.\n",
|
" 3. Um nun diese neu erstellte Code-Zelle zu editieren, klicken Sie diese mit dem Mauszeiger an. Die Zellenumrandung sollte von Blau auf Grün wechseln. Dies zeigt an, dass Sie sich nun im Editiermodus für dieses Zelle befinden.\n",
|
||||||
" 4. Nun könnt ihr die Summe aus zwei beliebigen ganzen Zahlen mit Hilfe der Syntax\n",
|
" 4. Nun können Sie die Summe aus zwei beliebigen ganzen Zahlen mit Hilfe des Syntax\n",
|
||||||
" ```python\n",
|
" ```python\n",
|
||||||
" 3 + 5\n",
|
" 3 + 5\n",
|
||||||
" ```\n",
|
" ```\n",
|
||||||
" berechnen.\n",
|
" berechnen.\n",
|
||||||
" 5. Um diese Code-Zelle auszuführen, müsst ihr anschließend die Tastenkombination: **STRG + ENTER** oder **SHIFT + ENTER** benutzen.\n",
|
" 5. Um diese Code-Zelle auszuführen, müssen Sie anschließend die Tastenkombination: **STRG + ENTER** oder **SHIFT + ENTER** benutzen. Das Ergebnis wird direkt unterhalb der Zelle angezeigt.\n",
|
||||||
" \n",
|
" \n",
|
||||||
" \n",
|
" \n",
|
||||||
"* Erstellt nun eine Markdown-Zelle oberhalb eurer Code-Zelle. Geht dabei wie folgt vor: \n",
|
"* Erstellen Sie nun eine Markdown-Zelle oberhalb ihrer Code-Zelle. Hierfür müssen Sie wie folgt vorgehen: \n",
|
||||||
" 1. Klickt eure zuvor erstellte Code-Zelle an. Sie sollte eine grüne Umrandung anzeigen, da ihr euch hier nach wie vor im Editiermodus befindet.\n",
|
" 1. Klicken Sie die zuvor erstellte Code-Zelle an. Die Zelle sollte eine grüne Umrandung anzeigen, da Sie sich nach wie vor im Editiermodus befinden.\n",
|
||||||
" 2. Drückt die **ESC**-Taste um vom Editier- in den Command-Modus zu wechseln (blaue Umrandung).\n",
|
" 2. Drücken Sie die **ESC**-Taste um vom Editier- in den Command-Modus zu wechseln (blaue Umrandung).\n",
|
||||||
" 3. Drückt nun die Taste **A** um eine neue Code-Zelle oberhalb (**A**bove) eurer angewählten Zelle zu erstellen. Euer Navigator wird wieder automatisch zu der neu erstellten Zelle springen.\n",
|
" 3. Drücken Sie nun die Taste **A** um eine neue Code-Zelle oberhalb (**A**bove) Ihrer angewählten Zelle zu erstellen. Der Navigator wird wieder automatisch zu der neu erstellten Zelle springen.\n",
|
||||||
" 4. Drückt nun die Taste **M** um die Code-Zelle in eine Markdown-Zelle zu verwandeln. Ihr werdet feststellen, dass eine Markdown-Zelle im Vergleich zu einer Code Zelle kein \"In []:\" auf der linken Seite stehen hat. \n",
|
" 4. Drücken Sie nun die Taste **M** um die Code-Zelle in eine Markdown-Zelle zu verwandeln. Sie werden feststellen, dass eine Markdown-Zelle im Vergleich zu einer Code Zelle kein \"In []:\"-Anzeige links der Zelle hat. \n",
|
||||||
" 5. Wechselt nun in der Markdown-Zelle in den Editiermodus (grüne Umrandung) in dem ihr sie anklickt. \n",
|
" 5. Wechseln Sie nun in der Markdown-Zelle in den Editiermodus (grüne Umrandung) in dem Sie diese anklicken. \n",
|
||||||
" 6. Fügt nun die folgenden Dinge in die Markdown-Zelle mit der entsprechenden Syntax ein:\n",
|
" 6. Fügen Sie nun die folgenden Objekte in die Markdown-Zelle mit dem entsprechenden Syntax ein:\n",
|
||||||
" * Eine level 1 und level 2 Überschrift\n",
|
" * Eine level 1 und level 2 Überschrift\n",
|
||||||
" * Eine numerische Aufzählung (1. 2. und 3.) wobei 1. ein fett gedrucktes Wort 2. ein kursive geschriebenes Wort und 3. ein Wort im true type beinhalten soll. \n",
|
" * Eine numerische Aufzählung (1. 2. und 3.) wobei 1. ein fett gedrucktes Wort 2. ein kursive geschriebenes Wort und 3. ein Wort im true type beinhalten soll. \n",
|
||||||
" * Fügt dem zweiten Aufzählungspunkt (2.) drei nicht nummerierte Unterpunkte hinzu.\n",
|
" * Fügen Sie dem zweiten Aufzählungspunkt (2.) drei nicht nummerierte Unterpunkte hinzu.\n",
|
||||||
" \n",
|
" \n",
|
||||||
"**Hinweise:**\n",
|
"**Hinweise:**\n",
|
||||||
"Um die Aufgabe mit der Markdown-Zelle zu lösen, könnt ihr die benötigte Syntax in der Zelle oberhalb dieser Aufgabe nach gucken. Wechselt hierzu in der entsprechenden Markdown-Zelle in den Editiermodus in dem ihr sie mit einem Doppelklick anwählt. \n",
|
"Um die Aufgabe mit der Markdown-Zelle zu lösen, können Sie den jeweils benötigten Syntax in der Zelle oberhalb dieser Aufgabe nach gucken. Wechselen Sie hierzu in der entsprechenden Markdown-Zelle in den Editiermodus in dem Sie die entsprechende Zelle mittels einem Doppelklick anwählen. \n",
|
||||||
"<div/>"
|
"<div/>"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -221,7 +222,7 @@
|
||||||
"* **F** für \"Find and Replace\" (nützlich wenn ihr zum Beispiel ein Variablennamen austauschen wollt)\n",
|
"* **F** für \"Find and Replace\" (nützlich wenn ihr zum Beispiel ein Variablennamen austauschen wollt)\n",
|
||||||
"* **I** + **I** Um den *\"Kernel\"* zu stoppen (wichtig falls ihr mal eine unendliche LOOP gebaut habt)\n",
|
"* **I** + **I** Um den *\"Kernel\"* zu stoppen (wichtig falls ihr mal eine unendliche LOOP gebaut habt)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Des weiteren könnt ihr [hier](https://www.cheatography.com/weidadeyue/cheat-sheets/jupyter-notebook/) eine Auflistung weiterer Jupyter-Befehle finden."
|
"Des weiteren können Sie [hier](https://www.cheatography.com/weidadeyue/cheat-sheets/jupyter-notebook/) eine Auflistung weiterer Jupyter-Befehle finden."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -304,6 +305,31 @@
|
||||||
"3**2 * 2 - 8 "
|
"3**2 * 2 - 8 "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2020-02-08T13:42:34.321719Z",
|
||||||
|
"start_time": "2020-02-08T13:42:34.291969Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"2.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"4**0.5"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
|
@ -388,6 +414,13 @@
|
||||||
"a"
|
"a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Variablen können neben einfach Buchstaben auch mittels komplexere Ausdrücke dargestellt werden. "
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
|
@ -413,7 +446,16 @@
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"a * variable"
|
"variable_die_eine_multiplikation_beinhaltet = a * variable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"variable_die_eine_multiplikation_beinhaltet"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -535,9 +577,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In der oberen Zelle ist **c** vom Datentyp `int` (*Integer*) was einer Ganzen Zahl entspricht. In der unteren Zelle jedoch ist **c** vom Datentyp `float` (*Floating Point Number*) also eine Gleitkommazahl. Dies liegt daran, das wir in der unteren Zelle **b** als Gleitkommazahl definiert haben. Um uns Arbeit abzunehmen hat Python für uns im Hintergrund dynamisch entschieden, dass somit **c** ebenfalls vom Typ `float` sein muss. \n",
|
"In der oberen Zelle ist **c** vom Datentyp `int` (*Integer*) was einer Ganzenzahl entspricht. In der unteren Zelle jedoch ist **c** vom Datentyp `float` (*Floating Point Number*) also eine Gleitkommazahl. Dies liegt daran, das wir in der unteren Zelle **b** als Gleitkommazahl definiert haben. Um uns Arbeit abzunehmen hat Python für uns im Hintergrund dynamisch entschieden, dass somit **c** ebenfalls vom Typ `float` sein muss. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Neben den primitiven Datentypen `float` und `int` gibt es noch die wichtigen Datentypen `str` (*string*) was einer Zeichenkette entspricht (z.B. Buchstaben, Wörter und Sätze), `complex` für Komplexe Zahlen und `bool` für Wahrheitswerte. Was genau Wahrheitswerte sind und für was diese verwendet werden, werdet ihr noch im **PGP2** lernen. \n",
|
"Neben den primitiven Datentypen `float` und `int` gibt es noch die wichtigen Datentypen `str` (*string*) was einer Zeichenkette entspricht (z.B. Buchstaben, Wörter und Sätze), `complex` für Komplexe Zahlen und `bool` für Wahrheitswerte. Was genau Wahrheitswerte sind und wofür diese verwendet werden, werden Sie noch im **PGP2** lernen. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Für das **PGP1** sind erstmal nur die Typen `int`, `float` und `str` von Bedeutung."
|
"Für das **PGP1** sind erstmal nur die Typen `int`, `float` und `str` von Bedeutung."
|
||||||
]
|
]
|
||||||
|
@ -559,7 +601,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"$s(t) = \\frac{1}{2}\\cdot a \\cdot t^2 + v_0 \\cdot t + s_0$\n",
|
"$s(t) = \\frac{1}{2}\\cdot a \\cdot t^2 + v_0 \\cdot t + s_0$\n",
|
||||||
"\n",
|
"\n",
|
||||||
"beschrieben werden. Hierbei beschreibt $t$ die verstrichene Zeit, $a$ die Beschleunigung, $v_0$ die Startgeschwindigkeit und $s_0$ die Startposition des Objekts. Verwende Variablen um die folgenden Werte zu berechnen:\n",
|
"beschrieben werden. Hierbei beschreibt $t$ die verstrichene Zeit, $a$ die Beschleunigung, $v_0$ die Startgeschwindigkeit und $s_0$ die Startposition des Objekts. Ersteklen Sie unterhalb der Aufgabe eine neue Code-Zelle und berechnen Sie die folgenden Werte:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Wie lange bräuchte ein Stift, welcher in einer Höhe von $s_0 = 1.2\\,$m losgelassen wird ($v_0 = 0\\,\\text{m}/\\text{s}$)... \n",
|
"Wie lange bräuchte ein Stift, welcher in einer Höhe von $s_0 = 1.2\\,$m losgelassen wird ($v_0 = 0\\,\\text{m}/\\text{s}$)... \n",
|
||||||
"\n",
|
"\n",
|
||||||
|
@ -590,9 +632,9 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## Zeichenketten\n",
|
"## Zeichenketten\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Wie eben bereits erwähnt, gibt es neben den Zahlen-Datentypen `int`, `float` und `complex` auch noch den Datentyp einer Zeichenkette `str`. Zeichenketten werden in Programmiersprachen vielseitig verwendet z.B. bei einer Nutzereingabe (wie dem Passwort), Dateiname bei einer Installation, oder bei Textrückgaben von Programmen. Letzteres haben wir bereits in Aufgabe 2 mit Hilfe der `print`-Funktion gesehen.\n",
|
"Wie eben bereits erwähnt, gibt es neben den Zahlen-Datentypen `int`, `float` und `complex` auch noch den Datentyp einer Zeichenkette `str`. Zeichenketten werden in Programmiersprachen vielseitig verwendet z.B. bei einer Nutzereingabe (z.B. einem Passwort), Dateiname bei einer Installation, oder bei Textrückgaben von Programmen. Letzteres haben Sie bereits in Aufgabe 2 a. mit Hilfe der `print`-Funktion gesehen.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Für das PGP-1 wollen wir uns zunächst darauf beschränken, dass Zeichenketten in so genannten **Formatstrings** dazu genutzt werden können, schönere `print` Rückgaben zu erzeugen bzw. wir mit Zeichenketten Achsenbeschriftungen an Graphen anbringen können. \n",
|
"Für das PGP-1 wollen wir uns zunächst darauf beschränken, dass Zeichenketten in so genannten **Formatstrings** dazu genutzt werden können, schönere `print` Rückgaben zu erzeugen, bzw. wir mit Zeichenketten Achsenbeschriftungen an Graphen anbringen können. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Zunächst erst aber einmal eine einfache Zeichenkette:"
|
"Zunächst erst aber einmal eine einfache Zeichenkette:"
|
||||||
]
|
]
|
||||||
|
@ -641,19 +683,29 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Einen **Formatstring** können wir über zwei Arten generieren (**Muss checken welche Python version im Hub genutzt wird**):"
|
"Einen **Formatstring** können wir über zwei Arten generieren"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": 1,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2019-10-27T12:25:06.344549Z",
|
"end_time": "2020-02-08T13:40:14.532316Z",
|
||||||
"start_time": "2019-10-27T12:25:06.333102Z"
|
"start_time": "2020-02-08T13:40:14.507294Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Dies ist Syntaxvariante eins\n",
|
||||||
|
"\n",
|
||||||
|
"Dies ist Syntaxvariante 2\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"a = 'eins'\n",
|
"a = 'eins'\n",
|
||||||
"b = 2\n",
|
"b = 2\n",
|
||||||
|
@ -672,39 +724,60 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": 2,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2019-10-27T12:25:06.359679Z",
|
"end_time": "2020-02-08T13:41:34.601805Z",
|
||||||
"start_time": "2019-10-27T12:25:06.347189Z"
|
"start_time": "2020-02-08T13:41:34.577256Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Dies ist pi auf 4 signifikante Stellen gerundet: 3.1416\n",
|
||||||
|
"\n",
|
||||||
|
"Dies ist pi auf 4 signifikante Stellen gerundet: 3.1416\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"pi = 3.1415926535\n",
|
"pi = 3.1415926535\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f'Dies ist pi auf 4 signifikante Stellen gerundet: {pi:.4}')\n",
|
"print(f'Dies ist pi auf 4 signifikante Stellen gerundet: {pi:.4f}')\n",
|
||||||
"print()\n",
|
"print()\n",
|
||||||
"print('Dies ist pi auf 4 signifikante Stellen gerundet: {:.4}'.format(pi))"
|
"print('Dies ist pi auf 4 signifikante Stellen gerundet: {:.4f}'.format(pi))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"... oder sofern ihr eine Rückgabe lieber über mehrere Zeilen ausgeben lassen wollt, könnt ihr dies wie folgt machen:"
|
"... oder sofern Sie eine Rückgabe lieber über mehrere Zeilen ausgeben lassen möchten, könnt Sie dies wie folgt machen:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": 5,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2019-10-27T12:25:06.380627Z",
|
"end_time": "2020-02-08T13:43:48.431735Z",
|
||||||
"start_time": "2019-10-27T12:25:06.359679Z"
|
"start_time": "2020-02-08T13:43:48.411817Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"An einem Widerstand R wurden die folgenden Werte gemessen:\n",
|
||||||
|
"Spannung: 12.0+/-0.1 V\n",
|
||||||
|
"Strom: 0.3+/-0.01 mA\n",
|
||||||
|
"Hierraus resultiert ein Widerstand von 40.0+/-1.37 kOhm \n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"U = 12.0 #V\n",
|
"U = 12.0 #V\n",
|
||||||
"dU = 0.1 #V\n",
|
"dU = 0.1 #V\n",
|
||||||
|
@ -717,7 +790,14 @@
|
||||||
"print(f'''An einem Widerstand R wurden die folgenden Werte gemessen:\n",
|
"print(f'''An einem Widerstand R wurden die folgenden Werte gemessen:\n",
|
||||||
"Spannung: {U}+/-{dU} V\n",
|
"Spannung: {U}+/-{dU} V\n",
|
||||||
"Strom: {I}+/-{dI} mA\n",
|
"Strom: {I}+/-{dI} mA\n",
|
||||||
"Hierraus resultiert ein Widerstand von {R}+/-{dR:.2} kOhm ''') "
|
"Hierraus resultiert ein Widerstand von {R}+/-{dR:.2f} kOhm ''') "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Hierbei zeigt `:` an, dass sie eine spezielle Formatierung verwenden möchten. Die Zahl hinter dem `.` gibt an wie viele Nachkommastellen Sie anzeigen lassen möchten. Das `f` bedeutet, dass es sich bei der Zahl um eine Gleitkommazahl handelt."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -728,10 +808,10 @@
|
||||||
" \n",
|
" \n",
|
||||||
"#### Aufgabe 2.b.: Beschleunigte Bewegung Zusatz\n",
|
"#### Aufgabe 2.b.: Beschleunigte Bewegung Zusatz\n",
|
||||||
" \n",
|
" \n",
|
||||||
"Lasst euch eure berechneten Werte aus Aufgabe 2 mit Hilfe von `print` erneut ausgeben. Nutzt jedoch dieses Mal **Formatstrings** für eine schönere und bedeutungsvollere Rückgabe. Achtet dabei besonders auf:\n",
|
"Lassen Sie nun Ihre berechneten Werte aus Aufgabe 2 mit Hilfe von `print` erneut ausgeben. Nutzen Sie jedoch dieses Mal **Formatstrings** für eine schönere und bedeutungsvollere Rückgabe. Achten Sie dabei ins besonders auf:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* Die Angabe der richtigen Einheiten\n",
|
"* Die Angabe der richtigen Einheiten.\n",
|
||||||
"* Das Runden der berechneten Werte der Anzahl an signifikanten Stellen entsprechend "
|
"* Das Runden der berechneten Werte der Anzahl an signifikanten Stellen entsprechend. "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -742,9 +822,9 @@
|
||||||
"\n",
|
"\n",
|
||||||
"Anstatt Berechnungen wie bei einem Taschenrechner immer wieder manuell einzugeben, ermöglicht uns eine Programmiersprache das Definieren von Funktionen. Funktionen können hierbei ähnlich wie mathematische Funktionen definiert und behandelt werden. Im folgenden wollen wir uns dies im Fall des Ohmschen Gesetzes, welches durch \n",
|
"Anstatt Berechnungen wie bei einem Taschenrechner immer wieder manuell einzugeben, ermöglicht uns eine Programmiersprache das Definieren von Funktionen. Funktionen können hierbei ähnlich wie mathematische Funktionen definiert und behandelt werden. Im folgenden wollen wir uns dies im Fall des Ohmschen Gesetzes, welches durch \n",
|
||||||
"\n",
|
"\n",
|
||||||
"$U(R, I) = R \\cdot I$ \n",
|
"$$U(R, I) = R \\cdot I$$ \n",
|
||||||
"\n",
|
"\n",
|
||||||
"beschrieben wird, angucken. Hierbei wird die Spannung $U$ durch die Variablen $R$ und $I$ beschrieben. Dies gilt auch analog für Funktionen in einer Programmiersprache:"
|
"beschrieben wird, angucken. Hierbei wird die Spannung $U$ durch die Variablen $R$ (Widerstand) und $I$ (Strom) beschrieben. Dies gilt auch analog für Funktionen in einer Programmiersprache:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -766,6 +846,8 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
|
"Bitte beachten Sie, dass die Rückgabe `return` der Funktion mit Hilfe der Tab-Taste eingerückt wurde. Dieser Syntax wird von Python vorgegeben uns muss eingehalten werden.\n",
|
||||||
|
"\n",
|
||||||
"Diese Funktion können wir nun auf Messdaten anwenden. Z.B. wir Messen bei einem Widerstand von $1\\,\\text{k}\\Omega$ einen Strom von $10\\,\\text{mA}$:"
|
"Diese Funktion können wir nun auf Messdaten anwenden. Z.B. wir Messen bei einem Widerstand von $1\\,\\text{k}\\Omega$ einen Strom von $10\\,\\text{mA}$:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -790,7 +872,136 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Neben mathematischen Funktionen, können Funktionen in einer Programmiersprache auch viel allgemeinere Aufgaben erfüllen bzw. komplexe Algorithmen beinhalten. Hierzu lernt ihr jedoch noch mehr in anderen Programmierkursen. Wie zum Beispiel:\n",
|
"Neben mathematischen Funktionen, können Funktionen in einer Programmiersprache auch viel allgemeinere Aufgaben erfüllen bzw. komplexe Algorithmen beinhalten. Hierfür benötigen wir meist mehr als nur eine Zeile. Um Python verständlich zu machen, dass mehre Zeilen zu einer Funktion gehören müssen wir die entsprechenden Zeilen wir zuvor den `return`-Befehl einrücken. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 7,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2020-02-08T14:00:35.030562Z",
|
||||||
|
"start_time": "2020-02-08T14:00:35.020705Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def komplxe_function(a, b, c, d):\n",
|
||||||
|
" result = a + b\n",
|
||||||
|
" result = result * c\n",
|
||||||
|
" result = result / d\n",
|
||||||
|
" return result"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2020-02-08T14:00:35.310478Z",
|
||||||
|
"start_time": "2020-02-08T14:00:35.290633Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"2.25"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"komplxe_function(1, 2, 3, 4)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Bitte beachten Sie, das Variablen welche in einer Funktion definiert und genutzt werden auch nur dort zur Verfügung stehen. Versuchen Sie die entsprechenden Variablen im regulär im Notebook zu verwenden werden Sie einen Fehler bekommen."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 9,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2020-02-08T14:01:53.810639Z",
|
||||||
|
"start_time": "2020-02-08T14:01:53.785432Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"ename": "NameError",
|
||||||
|
"evalue": "name 'result' is not defined",
|
||||||
|
"output_type": "error",
|
||||||
|
"traceback": [
|
||||||
|
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
|
||||||
|
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
|
||||||
|
"\u001b[1;32m<ipython-input-9-0ac921c19f1a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mresult\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
|
||||||
|
"\u001b[1;31mNameError\u001b[0m: name 'result' is not defined"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"result"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Sollten Sie das Ergebnis dennoch in einer Variablen speichern wollen können Sie dies natürlich machen:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 11,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2020-02-08T14:04:10.690109Z",
|
||||||
|
"start_time": "2020-02-08T14:04:10.670371Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"result = komplxe_function(1, 2, 3, 4)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 12,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2020-02-08T14:04:10.890200Z",
|
||||||
|
"start_time": "2020-02-08T14:04:10.870502Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"2.25"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 12,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"result"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Noch mehr über komplexere Programme und Algorithmen lernen Sie in Veranstaltungen wie\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* Computer in der Wissenschaft \n",
|
"* Computer in der Wissenschaft \n",
|
||||||
"* Programmieren für Physiker\n",
|
"* Programmieren für Physiker\n",
|
||||||
|
|
Loading…
Reference in a new issue