/
Python, Programmieren macht Spaß
1 Einführung
[toc]
Python ist eine universelle, interpretierte höhere
Programmiersprache. Ihre Entwurfsphilosophie betont
Programmlesbarkeit. Die Programmstruktur wird durch die
Einrücktiefe gebildet. Quelle: Wikipedia
2 Wie bin ich zu Python gekommen?
[toc]
- Vor des Studiums (1989-): BASIC (C64), etwas Assembler, Turbo Pascal.
- Während dem Studium (1996-): Unix-Shell, C, C++, Java, Prolog, Lisp, Visual Basic.
- In der Freizeit: Perl
- Programmieren machte mir Spaß, aber alle Sprachen fühlten sich etwas sperrig (zu kompliziert) an.
- 2001: Suche nach Alternative: Ruby oder Python. Ich wählte bewusst Python.
- Seit 2001: arbeitstäglich Python.
3 Begeisterung
[toc]
-
Die Programmiersprache Python bietet sehr viele Bibliotheken. Die
Module aus der Standardbibliothek werden gut gepflegt.
-
Man bekommt bei Fehlern immer einen Stacktrace mit Zeilennummer des
Fehlers. In "C" muss man dafür extra den Debugger starten.
-
Segmentation Faults sind fast unmöglich --> Programmentwicklung ist
schneller und sicher.
-
Die Entwicklungsgeschwindigkeit ist meistens wichtiger als die
Ausführungsgeschwindigkeit. Zeitkritische Abschnitte
können später in C oder C++ geschrieben werden.
-
Keine Makefiles mehr: Die
vorkompilierten PYC-Dateien (Bytecode) werden automatisch neu
erstellt, falls sich die zugehörige PY-Datei geändert hat.
- Die Lizenz ist nicht GPL. Python lässt sich ohne Probleme
auch in kommerziellen (Closed Source) Projekten verwenden. Siehe Python Licence.
- Die Schlüsselwörter und Funktionen heißen meist enstsprechend dem
ANSI-C, bzw. POSIX Standard. Erfahrende Programmierer finden sich
schnell zurecht.
- Python hat eine riesige Community. Fragen werden bei
zB Stackoverflow innerhalb
weniger Minuten beantwortet.
Hier die Anzahl der Fragen/Antworten im Verlauf
der letzten Jahre auf StackOverflow (2008 bis 2022):
Google
Trends (2008 bis 2022):
4 Vorbereitung für Workshops
[toc]
Kursteilnehmer sollten vor dem Workshop:
- In der Lage sein englischsprachige Dokumentation zu verstehen.
- Sich mit einem Texteditor oder IDE auskennen (pyCharm, Emacs, vim, gedit, IDLE, ...)
- WLAN am Laptop einrichten
- Python installieren
- Interaktiven Interpreter aufrufen ... dort zB help(list) oder rechnen: (5 + 10**5) * 2
- Es wird mindestens Python 3.8 vorausgesetzt.
5 Beispiel: Taschenrechner
[toc]
6 Datentypen
[toc]
Datentypen werden dynamisch vergeben.
6.1 Übersicht
[toc]
Integer |
i = 1 |
Ganzzahl |
Float |
f = 0.1 |
Gleitkommazahl |
String |
s = 'hallo' |
Unicode-Zeichenkette |
Bytes |
b = b'\x00\x01....' |
Binäre Bytes |
Liste |
l = [1, 2, 3] |
Veränderbare Liste |
Tuple |
t = (1, 2, 3) |
Unveränderbare Liste |
Menge |
z = set([1, 1, 2, 2, 3]) --> set([1, 2, 3]) |
Menge (ohne Dopplungen) |
Dictionary |
d = {1: 'eins', 2: 'zwei', 3: 'drei'} |
Auch Hash oder assoziatives Array genannt. |
6.2 Zahlen
[toc]
Es gibt die Datentypen Integer/Ganzzahlen (int), Float/Gleikommazahlen
sowie Dezimalzahlen beliebiger Genauigkeit.
i = 1 # Zuweisung
i += 1 # i++ wie in C gibt es nicht
i *= 2
i**2 # i "hoch" 2
docs.python.org:
Operatortabelle: Numeric Types
6.3 Zeichenketten
[toc]
-
Strings (Zeichenketten) sind eine Folge von Zeichen. Man muss sich
nicht um die Terminierung von Zeichenketten, wie z.B. in C kümmern.
- Zeichenketten können in einfachen oder doppelten
Anführungszeichen geschrieben werden. Mehrzeilige Zeichenketten sind
durch dreifache Anführungszeichen möglich:
s1 = 'Beispiel'
s2 = 'Er sagte "Hallo" zu mir'
s3 = "er ist der 20'te"
s4 = """Mehrere Zeilen
Zeile 2
Zeile 3
"""
s5 = '''Ebenfalls mehrere
Zeilen
'''
- Für die Stringformatierung gibt es drei Varianten. Ich stelle hier die aktuellste Variante (F-String) vor.
Verfügbar ab Python 3.6:
s = 'Sonne'
m = 'Mond'
t = 'Sterne'
satz = f'{s}, {m} und {t}'
--> Sonne, Mond und Sterne
# HTML erstellen
import datetime
heute = datetime.date.today().strftime('%d.%m.%Y')
title = 'Das ist der Titel' # Wird zweimal verwendet.
# Im Kopf, und als <h1>
html = f'''
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</title>
...
Heute ist der {heute}
....
</body>
</html>'''
docs.python.org: Text
Sequence Type
- Slices (Aus einem Teilbereich einer Liste eine neue Liste erstellen)
s = 'abcdefg'
# Erstes Zeichen
s[0] # --> 'a'
# Letztes Zeichen
s[-1] # --> 'g'
# Zugriff auf Teile der Liste
s[:4] # --> 'abcd'
s[1:4] # --> 'bcd'
s[-2:] # --> 'fg'
Sequence Types
(Für Zeichenketten, Listen, Tuples, ...)
-
Zeichenketten können, sollten aber nicht, mit dem Plus Operator
verbunden werden. Es ist effizienter mit einer Liste zu arbeiten:
s = []
for i in range(10):
s.append(str(i))
s = ''.join(s)
assert s == '0123456789'
- Die in C üblichen Sonderzeichen sind vorhanden:
\n == Newline (Zeilenumbruch)
\r == Carriage Return
\t == Tabulator
\\ == Backslash
Möchte man das Interpretieren der Escape Sequenzen unterbinden,
kann dies durch ein vorangestelltes 'r' geschehen.
s = 'a\nb' # --> \n wird zu einem Newline
s = r'a\nb' # --> \n wird *nicht* zu einem Newline
- Weiteres
-
# Länge
len(s)
-
# Substring
if 'oma' in 'Thomas':
...
-
# Auftrennen an Leerzeichen:
satz = 'Aller Anfang ist schwer'
satz.split() # --> ['Aller', 'Anfang', 'ist', 'schwer']
-
dateiname = 'foo.PNG'
if dateiname.lower().endswith('.png'):
...
-
# Ist das eine Zeichenkette?
if isinstance(myvar, str):
print('ja, das ist ein String')
- Unicode
unicode_string = 'üöäßÜÖÄ'
print(len(unicode_string)) # Länge: 7
byte_string = unicode_string.encode('utf8') # Wandeln von der wunderschönen Unicode-Zeichenkette zur hässlichen Bytefolge
print(len(byte_string)) # Länge: 14
unicode_again = byte_string.decode('utf8') # Wandeln von hässlichen Bytefolge zur wunderschönen Unicode-Zeichenkette
6.4 Listen
[toc]
-
Strings und Tuples sind 'immutable', d.h. sie können
nicht verändert werden. Listen sind im Gegensatz dazu veränderbar.
-
Es können beliebig Listeneinträge hinzugefügt oder entfernt werden.
Die Länge muss nicht wie in vielen anderen Programmiersprachen vorher
definiert werden.
- Der erste Eintrag in einer Liste wird mit einer Null angesprochen.
- Code:
mylist = ['Das', 'Wetter']
mylist.append('schön')
mylist[1] = 'Leben'
mylist.insert(2, 'ist')
print(mylist) # Das Ergebnis?
- Listen von Listen
mylist[1] = [3, 4]
- Schleife über 3'er Tupel
zahlen = [(1, 'eins', 'one'),
(2, 'zwei', 'two'),
(3, 'drei', 'three')]
for i, deutsch, englisch in zahlen:
...
docs.python.org: Operatortabelle:
Mutable Sequence Types
6.5 Dictionaries (Hash-Tables)
[toc]
docs.python.org: Operatortabelle:
Mapping Types
7 Sonstiges
[toc]
Folgende Schlüsselwörter haben eine besondere Bedeutung:
True |
Boolscher Wert für Wahr |
False |
Boolscher Wert für Falsch |
None |
Leerer Wert, NIL, Null-Pointer |
7.1 Booleschen Funktion
[toc]
Variable1 |
Boolescher Operator |
Variable2 |
Ergebnis |
True |
and |
True |
True |
True |
and |
False |
False |
False |
and |
False |
False |
False |
and |
True |
False |
Variable1 |
Boolescher Operator |
Variable2 |
Ergebnis |
True |
or |
True |
True |
True |
or |
False |
True |
False |
or |
False |
False |
False |
or |
True |
True |
8 Flusssteuerung
[toc]
-
#!/usr/bin/env python3
my_string = input('Bitte Zahl eingeben: ')
my_string = my_string.strip() # Newline (\n) am Ende der Eingabe entfernen
i = int(my_string)
if i<0:
print(f'{i} ist kleiner als Null.')
elif i==0:
print(f'{i} ist gleich Null.')
else:
print(f'{i} ist größer als Null.')
- Die Blockstruktur wird durch das Einrücken mit vier Leerzeichen
gekennzeichnet.
for x in [1, 2, 3, 4]:
print(x)
for x in range(6):
if x == 1:
# Überspringe diese Zahl
continue
if x == 4:
# Beende die Schleife
break
print(x)
- While-Schleife:
mylist = [1, 2, 3, 4]
while mylist:
print(mylist.pop())
9 Funktionen
[toc]
-
Funktionen werden durch das Schlüsselwort 'def' definiert:
def plus(a, b):
return a+b
print(plus(5, 7))
--> 12
- Parameter werden Call By Assignment übergeben. Beim
Funktionsaufruf werden die Parameter den lokalen Variablen
zugewiesen.
def fuelle_liste(liste):
liste.append('eins')
liste.append('zwei')
liste.append('drei')
liste = []
fuelle_liste(liste)
print(liste)
--> ['eins', 'zwei', 'drei']
- Default Argumente:
def printEtwas(etwas='Gurkensalat'):
print(etwas)
printEtwas()
--> Gurkensalat
printEtwas('Tomatensuppe')
--> Tomatensuppe
- Keyword Arguments:
Argumente die per Schlüsselwort gesetzt werden
sind sehr nützlich, da man sich bei Funktionen mit vielen Parametern
nicht die Reihenfolge merken muss:
def berechneWiderstand(volt, ampere):
return volt/ampere
print(berechneWiderstand(volt=12, ampere=4))
print(berechneWiderstand(ampere=4, volt=12))
10 Python-Datei
[toc]
Ein Python Script wird in einer Datei gespeichert, die mit ".py"
endet. Als Vorlage kann folgende Datei dienen: reverse.py
Wie führt man nun dieses Programm aus?
Unter Unix ruft man es von der Shell auf:
python3 myscript.py
Steht in der ersten Zeile #!/usr/bin/env python3 und hat man die
Ausführungsrechte gesetzt (chmod a+rx myscript.py) kann man es direkt
ausführen:
./myscript.py
Unter Windows kann man ein Script durch Doppelklick aus dem
Explorer ausführen. Endet die Datei mit ".py" wird es in einer
MS-DOS Eingabeaufforderung ausgeführt. Wenn es die Endung ".pyw" hat,
wird es ohne zusätzlichem Fenster gestartet. Der Nachteil vom
Anklicken ist, das man dem Script keine Argumente übergeben kann. Zur
Not kann man das Script aus der MS-DOS Eingabeaufforderung aufrufen
und dort Argumente übergeben.
Startet man ein Programm durch Doppelklick auf eine .py Datei,
schließt sich das Fenster sobald das Script beendet ist. Möchte man,
dass das Fenster offen bleibt, kann man ein "sys.stdin.readline()" am
Ende einfügen.
Ein typischen Kommandozeilenprogramm in Python:
#!/usr/bin/env python3
import argparse
def main():
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
args = parser.parse_args()
print(args.integers)
if __name__ == '__main__':
main()
Die Funktion "main()" wird aufgerufen, wenn das Script aufgerufen
wird.
Wird das Script von einer anderen Datei importiert (import
myscript
), wir die Main-Funktion nicht aufgerufen. Es werden dann nur
die Funktionen und Klassen bereitgestellt.
11 Dateien
[toc]
- Arbeiten mit Dateien ist einfach:
- Code:
with open('beispiel.txt') as fd:
inhalt = fd.read() # Lese die gesamte Datei
# ein schließen von fd ist nicht nötig, wenn mit "with" gearbeitet wird.
print(inhalt)
Oder zeilenweise:
with open('beispiel.txt') as fd:
for line in fd:
print(line, end='')
12 Klassen - Objektorientierung
[toc]
-
Klassen sind Datenstrukturen, die aus Methoden und Attributen bestehen.
Methoden sind Funktionen einer Klasse, und Attribute sind Daten einer
Klasse. Ein Beispiel: klasse-auto.py
-
Python unterstützt auch Vererbung, sowie Mehrfachvererbung und
Exceptions.
- Alle Methoden und Attribute sind 'public'. Beginnt der Name mit
einem Unterstrich, ist das nur ein Hinweis, dass darauf von außen
nicht zugegriffen werden soll.
- Aber bitte beachten: OOP kann Quelltext auch unnötig kompliziert machen.
13 Exceptions
[toc]
my_int = 'sf'
try:
my_int2 = my_int + 3
except TypeError as exc:
print(f'etwas ging schief: {exc}')
else:
print('alles ging gut')
print('hier geht es weiter')
14 Standardbibliothek
[toc]
14.1 Module importieren
[toc]
Ein Modul (bzw. Bibliothek) wird mit der import-Anweisung
eingebunden. Die Funktionen, Variablen und Klassen dieses Moduls sind
über den Modulnamen anzusprechen. Hier zwei Beispiele:
import sys
sys.argv[0] # Scriptname
import json
json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
14.2 Paketauswahl
[toc]
Folgende Pakete gehören zur Standardbibliothek und sind immer vorhanden. Da die gesamte Liste der Python Pakete inzwischen
recht lang geworden ist, will ich hier die aus meiner Sicht
wichtigsten Pakete aufzählen:
- re:
Python unterstützt reguläre Ausdrücke (Regular Expressions). Es
wird die Bibliothek PCRE (Perl
Compatible Regular Expressions) verwendet.
Bitte beachten: Das Verwenden von Reguläre Ausdrücke ist vergleichbar mit dem Versuch aus Kartoffelbrei
wieder Kartoffeln zu machen. Wo wurden die Daten in einer Zeichenkette gestampft, so dass man nun wieder aus
dem Brei die Daten herausfischen muss? Wir leben im 21-Jahrhundert. Warum kann die Datenquelle nicht JSON
o.ä. liefern?
- sys:
Sys enthält unter anderem:
sys.exit() sofortiges Beenden des Programms
sys.stdin, sys.stdout, sys.stderr
sys.argv Liste der Argumente beim Programmaufruf.
Der Scriptname steht in sys.argv[0]
- os:
Betriebsystemfunktionen (meist entsprechend POSIX):
os.chdir(), os.getcwd(), os.nice(), os.kill(),
os.chmod(), os.environ['PATH'],
os.walk() (ähnlich wie 'find')
- datetime:
Datumsfunktionen, besser als das Modul "time", da nicht nur in der
Einheit "Sekunden seit 1970" gerechnet wird.
- email: Emails im MIME-Format bearbeiten.
- subprocess:
Sicheres Ausführen von Prozessen. Es wird direkt der entsprechende Programm (zB "ping") aufgerufen (ohne
Shell zwischen Python und ping Prozess). Der Parameter shell=True sollte vermieden werden.
Beispiel:
form = cgi.parse()
# Test ob Rechner 'hostname' per Ping erreichbar ist
hostname = form.getfirst('hostname')
ret=subprocess.run([f"ping -c1 '{hostname}'"], shell=True)
--> Achtung: Ein Angreifer kann "myhost'; rm -rf /" übergeben!
Besser:
ret = subprocess.run(['ping', '-c1', form.getfirst('hostname')])
--> Es wird direkt Ping und nicht erst eine Shell aufgerufen.
Hinweis: Das Aufrufen von Programmen per subprocess sollte, falls möglich, vermieden werden. Inzwischen gibt
es für fast alle Anwendungsfälle eine entsprechene Bibliothek auf pypi. Es ist
deutlich effizienter eine Bibliothek aufzurufen.
- logging:
# Verwendung in einem Modul
import logging
logger = logging.getLogger(__name__)
def foo():
...
logger.info('Sun is shining')
- Während das Logging in vielen Module verwendet wird (siehe oben) wird das Logging nur an einer
Stelle konfiguriert.
- Siehe docs.python.org: logging
- argparse: Für nutzerfreundliche
Kommandozeilen Tools.
- mock:
"to mock" heißt "Vortäuschen". Das ist in Tests sehr sinnvoll: einzelne Methoden in Tests ersetzen. Bsp: Im
Test möchte man zB keine Netzwerverbindung voraussetzen. Mittels mock können insbesondere dritt-Systeme
vorgetäuscht ("weg-gemockt") werden.
Man sollte es aber nicht übertreiben. Tests mit zu viel mocking werden unübersichtlich.
15 Externe Bibliotheken
[toc]
- Django
Web-Framework.
- DB-API:
Anbindung an relationale Datenbanken: PostgreSQL (psycopg2), MySQL, Oracle, ...
- pytest:Tool für Unittesting mit Python. Inkl guter
Doku. Besonders gern mag ich "py.test -k myterm" um alle Tests aufzurufen die "myterm" im Namen haben.
- requests: "Requests is an HTTP library,
written in Python, for human beings." Besser als die Bibliotheken aus der Standardlib (urllib2)
16 Tools von mir
[toc]
17 Texte von mir
[toc]
18 Beispiele
[toc]
19 Externe Links
[toc]
20 Vergleich mit anderen Programmiersprachen
[toc]
Siehe Vergleich von mir bekannten Programmiersprachen
- Was bedeutet "from myapp.models import MyModel"?
In der Regel lässt sich das wie folgt auflösen:
- myapp: Verzeichnis inkl. __init__.py Datei
- models: Datei models.py
- MyModel: Klasse in models.py
- Wie kann man Bild-Dateien mit Python bearbeiten?
- Pillow: Python Bibliothek für Bildbearbeitung
- Aufruf von ImageMagick per subprocess.
Hier ein Beispiel um mit 'convert' von ImageMagick
Bilder zu skalieren:
import subprocess
filename = 'test.jpg'
filename_small = 'klein.png'
subprocess.check_call(['convert', '-geometry', '128x128', filename, filename_small])
- Andere Möglichkeiten sind hier zu finden: pythonvision.org
- Wie funktioniert der Debugger von Python?
Ich verwende den Debugger selten. Ich verwende sehr kurze Edit-Test-Zyklen, und
spicke den Quelltext mit "assert 0, my_var" Anweisungen, wenn ich
einen Fehler suche. In PyCharm gibt es einen Debugger, den ich aber auch nur selten verwende.
- Welchen Editor, welche IDE sollte man benutzen?
vim, Emacs, gedit, ...
Ich selbst nutze
seit 2015 PyCharm. Vorher: 2001-2015 Emacs.
- Wo finde ich eine Übersicht der Funktionen, Module und Klassen?
docs.python.org -->
Library Reference -->
Quick search (links)
- Wie kann ich eine GUI mit Python entwickeln?
Mein Tipp: Entwickle eine Web-GUI. Aus meiner Sicht sind native-GUIs (qt, gtk, tkinter, ...) nicht mehr
zeitgemäß.
Wenn du zB Django lernst, dann lernst du dabei Dinge, die aus meiner Sicht deutlich mächtiger sind.
- Wie wird aus dem Code ein Paket, dass andere installieren können?
Python Packaging User Guide
- Wie kann ich auf dem Laufenden bleiben? Gibt es Newsletter?
Liste von Newsletter
- Das RPM/DPKG für Modul X ist sehr veraltet. Was tun?
Ich installiere nur Python aus der Paketquelle des Betriebssystems
(RPM/DPKG). Alle anderen Abhängigkeiten (Django, psycopg2, ...) werden
über pip in
einer virtualenv
installiert.
- Ich benötige ein ORM (object-relational
mapping)
Ich würde Django nehmen, auch wenn die Anwendung nichts mit Web oder HTML zu tun hat. Insbesondere das
Ändern des Datenbankschemas (Migration) ist damit super einfach.
22 Python++
[toc]
Folgende Abschnitte sind für Fortgeschrittene.
22.1 List Comprehension
[toc]
# Mit einer Schleife Leerzeichen am Anfang/Ende entfernen.
fruechte = [' Apfel ', ' Banane ', ' Kiwi ', ' Ananas']
neue_fruechte = []
for frucht in fruechte:
frucht = frucht.strip()
neue_fruechte.append(frucht.strip())
fruechte = neue_fruechte
# List Comprehension (einiges kürzer)
fruechte = [frucht.strip() for frucht in fruechte]
22.2 Decorator
[toc]
Mit einem Decorator wird eine Funktion 'verkleidet'. Folgendes
Beispiel implementiert den Decorator 'commit_on_success'.
#!/usr/bin/env python3
def begin():
print('begin')
def commit():
print('commit')
def rollback():
print('rollback')
def commit_on_success(func):
'''
Führe commit() aus, falls die dekorierte Funktion keine Exception
wirft. Ansonsten wird rollback() aufgerufen.
'''
def _commit_on_success(*args, **kw):
begin()
try:
res = func(*args, **kw)
except Exception as e:
rollback()
raise # Re-raise (aufgefangene Exception erneut werfen)
else:
commit()
return res
return _commit_on_success
@commit_on_success
def foo(do_raise):
if do_raise:
raise Exception()
foo(False) # --> commit()
foo(True) # --> rollback()
user@host> python deco.py
begin
commit
begin
rollback
Traceback (most recent call last):
File "tmp/deco.py", line 32, in <module>
foo(True) # --> rollback()
File "tmp/deco.py", line 17, in _commit_on_success
res = func(*args, **kw)
File "tmp/deco.py", line 29, in foo
raise Exception()
Exception
'''
22.3 Properties
[toc]
class MailAddress(object):
def __init__(self, user_at_domain):
self.user_at_domain = user_at_domain
@property
def domain(self):
return self.user_at_domain.split('@')[1]
mail = MailAdress('me@example.com')
print(mail.domain) # --> 'example.com'
Impliziter (versteckter) Funktionsaufruf. Siehe docs.python.org: Built-in Function property
22.4 Generators
[toc]
Generatoren verhalten sich wie Listen. Es wird 'on-the-fly' für jeden
Schleifendurchlauf das aktuelle Element zurückgegeben. Dieses
Verfahren verbraucht weniger Hauptspeicher. Hier eine Nachbildung der
Funktion range():
def my_range():
i = 0
while True:
yield i
i+=1
for i in my_range():
print(i)
if i == 5:
break
Siehe auch docs.python.org: Iterator
und docs.python.org: yield
23 Debugging Tipps
[toc]
Hier einige Hinweise zum Auffinden von Fehlern:
- Mein Vorgehen:
- Schreibe parallel zum eigentlichen Quellcode einen Test.
- Rufe den Test auf.
- Es wird vermutlich auf Grund eines Fehlers einen Stacktrace geben.
- In der Regel ist der fremde Quelltext OK. Also suche die erste Zeile (unten beginnend), die von dir
ist.
- Öffne die Datei und springe (das Suchen per Auge ist zu anstrengend) zu der passenden Zeile.
- Warum könnte es zu dem Fehler kommen? Vermutlich willst du wissen was in Variablen steht und wie der
Interpreter an diese Stelle kommt.
- Füge zB
assert 0, repr(myvar)
oder print/logging Anweisungen ein.
- Rufe den Test erneut auf.
- Den Ablauf wiederholen bis der Fehler gefunden wurde.
- Aktuellen Stack ausgeben:
import traceback
print(''.join(traceback.format_stack()))
# Erklärung: Wenn man weiß wo ein Fehler auftritt, aber nicht weiß welche
# Stellen die Funktion aufrufen, sieht man die verschachtelten Funktionsaufrufe,
# die zum Ausführen der entsprechenden Zeilen führten.
24 Spaßbremse
[toc]
Auch wenn Programmieren Spaß macht, bedenke folgendes:
- "Bad programmers worry about the code. Good programmers worry about data structures and their
relationships." (Linus Torvalds (Erfinder und Hauptentwickler von Linux))
- Schleifen macht die Datenbank (zB PostgreSQL) deutlich schneller als Python. SQL ist zwar stinklangweilig,
aber oft sind die Mengenoperationen mächtiger als Schleifchen in Scriptsprachen.
Also
- Für mich heißt das: Speichere alles in PostgreSQL. Auch Konfiguration (auch wenn es erst schwer fällt Konfig
in der DB zu verwalten. Denn als Entwickler liebt man doch Versionsverwaltung mit git).
- Verwende Bibliotheken, anstatt das Rad neu zu erfinden. Auf PyPi gibt es viele nützliche Tools: pypi
- Sprich mit anderen bevor du programmierst. Frage auf Mailinglisten oder StackOverflow.
- Skizziere Screenshosts. Zum Beispiel auf DIN-A4 im Querformat. Nicht mit einem Programm (Visio/Inkscape),
denn das frisst viel Zeit.
- Mache dir erst über die Datenstruktur gedanken. Beachte die Kardinalitäten (1:1, 1:N, N:M). Schlechte
Algorithmen können leichter ersetzt werden als schlechte Datenstrukturen.
25 Infrastruktur
[toc]
- Meine persönlichen (nicht allgemeingültigen) Tipps
- Jede Zeile Quelltext ist unter Versionskontrolle. Auch wenn du alleine programmierst.
- Systeme sollten mit einem Befehl erstellt und getestet werden können. Also ggf inkl. Nutzer anlegen,
DB-Anlegen, Webserver Konfig erstellen ...
- "Verheirate" dich nicht mit deinen Einstellungem am PC. Du solltest in wenigen Minuten auf einem neuen PC
arbeiten können. Hintergrund: Ansonsten wird es bald Code (und Tests) geben, die Aufgrund bestimmter
Einstellungen nur bei dir funktionieren. Bei anderen kommt es dann zu ggf unklaren Fehlern. Vermeide das.
Die Arbeitsumgebung sollte möglich simple (ggf automatisiert) erstellt werden können.
- Verwende CI
- Verwende Python Packages mit setup.py
- Installiere per pip
- Verwende virtualenv in der Entwicklungsumgebung.
- Entwickle nicht in einem Container.
- Falls du Server beim Entwickeln brauchst, die dein PC nicht hat, nehme für diese Server Docker.
- Dann ist Continuous Delivery nicht mehr
weit.
26 My personal programming guidelines
[toc]
Seit Juli 2016 pflege ich meine Tipps zur Softwareentwicklung hier: My personal programming guidelines
Diese Seite entstand im Rahmen folgender Vorträge und Workshops:
- Linux User Group Dresden
Februar 2002.
- Linux-Info-Tag Dresden: 2003, 2004 (mit Arnd Bäcker), 2005,
2006, 2007.
- Chemnitzer Linux-Tage: 2005, 2006 (mit Josef Spillner), 2007, 2008, 2012, 2014 (mit Stefan Schwarzer), 2017, 2018, 2019, 2021, 2022
© 2002-2022 Thomas Güttler. Der Text darf nach belieben
kopiert und modifiziert werden, solange dieser Hinweis zum
Copyright und ein Links zu dem Original unter www.thomas-guettler.de
erhalten bleibt. Es wäre nett, wenn Sie mir Verbesserungsvorschläge
mitteilen:
guettli@thomas-guettler.de