====== Python ======
Python ist eine interpretierte höhere Programmiersprache, die häufig als Skriptsprache eingesetzt wird.
Die Version Python 2 wird seit April 2020 nicht mehr unterstützt.
===== Übersicht über nützliche Bibliotheken =====
^Name ^Einsatzzweck ^
|[[https://configobj.readthedocs.org|configobj]] |Parsen von Konfigurationsdateien|
|[[https://docs.python.org/3/library/argparse.html|argparse]] |Parsen von Kommandozeilenoptionen, auch zum Parsen von Konfigurationsdateien, configobj ist dabei jedoch komfortabler|
|[[http://matplotlib.org|matplotlib]] |Erzeugen von Plots|
|[[http://pandas.pydata.org|pandas]] |Datenanalyse|
===== Standard-Library =====
==== Switch-Case ====
Python kennt keine Switch-Case-Anweisung.
Die Funktion kann mit If-Else-Anweisung nachgebildet werden, es gibt aber auch [[http://www.pydanny.com/why-doesnt-python-have-switch-case.html|weitere Möglichkeiten]].
==== For-Schleifen ====
In der normalen For-Schleife mit range müssen die Argumente Integers sein:
for i in range(start, stop, step):
Sind sie Floats kann arange aus numpy verwendet werden:
for i in numpy.arange(start, stop, step):
Für eine feste Anzahl von Schritten, kann linspace verwendet werden:
for i in numpy.linspace(start, stop, nrSteps):
Wird der Index einer For-Schleife benötigt, kann ''enumerate'' verwendet werden:
ints = [8, 23, 45, 12, 78]
for idx, val in enumerate(ints):
print idx, val
==== String-Formatting ====
Python unterstützt zwei verschiedene Möglichkeiten zur Stringinterpolation: den ''%''-Operator und ''[[https://docs.python.org/2/library/string.html#formatstrings|.format()]]''. Letzteres ist die neuere und empfohlene Variante.
Beispiel:
#alt
'%s %s' % ('eins', 'zwei')
#neu
'{} {}'.format('eins', 'zwei')
* [[https://mkaz.blog/code/python-string-format-cookbook/|Python String Format Cookbook]]
* [[https://pyformat.info/|pyformat.info]] viele Beispiele mit Gegenüberstellung von alter und neuer Variante
=== Bools ausgeben ===
Um boolsche Werte in anderen textueller Darstellung als ''True''/''False'' auszugeben kann man diesen Trick verwenden:
print "state: {0}".format(['Off','On'][state])
==== Modul neu laden ====
Um ein bereits importiertes Modul neu zu laden (z.B. um globale Variablen zurück zu setzen), muss ein ''reload'' durchgeführt werden.
Je nach Python-Version liegt diese Funktion in einem anderen Modul:
^Python-Version ^Befehl^
|2 |reload(module)
|
|3-3.3 |import imp
imp.reload(module)
|
|>3.4 |import importlib
importlib.reload(module)
|
==== Buffering ====
Standardmäßig ist die Ausgabe von Python gebuffert.
Das kann insbesondere bei der Verwendung von Umleitungen ''command > out.txt'' oder dem Einsatz von ''tee'' (''command | tee out.txt'') und langen Skriptlaufzeiten störend sein.
Folgende Möglichkeiten existieren zur Lösung:
* Mit ''sys.stdout.flush()'' explizit einen Flush des Buffers anfordern
* Das Skript mit ''python -u'' aufrufen (geht auch in Shebang-Zeile). Damit sind alle Ausgaben ungebuffert.
* Seit Python 3.3 kennt ''print'' den Parameter ''flush'': print('Test', flush=True)
* Vor dem ersten ''print''-Befehl folgendes aufrufen: sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Damit sind alle Ausgaben ungebuffert.
[[http://stackoverflow.com/questions/230751/how-to-flush-output-of-python-print|Quelle]]
==== mehrfache Einträge aus Liste entfernen ====
Mehrfache Einträge aus Listen lassen sich durch die Umwandlung in ein Set (und eine Rückumwandlung in eine Liste) entfernen:
unique_list = list(set(nonunique_list))
Die Einträge sind dann ungeordnet.
==== String zu Liste konvertieren ====
Soll ein String zu einer Liste mit einem Element umgewandelt werden, können eckige Klammern ''[]'' verwendet werden:
test_string = "abc"
text_list = [test_string]
#text_list = ["abc"]
Der Befehl ''list'' erzeugt dagegen eine Liste bestehend aus den einzelnen Zeichen des Strings:
test_string = "abc"
text_list = list(test_string)
#text_list = ['a', 'b', 'c']
==== NaN erzeugen ====
Ein NaN (Not a Number) kann mit ''float('NaN')'' erzeugt werden.
Seit Python 3.5 kann auch ''math.nan'' verwendet werden.
==== Exceptions ====
* [[https://web.archive.org/web/20220211170740/https://julien.danjou.info/python-exceptions-guide|The definitive guide to Python exceptions]]
* [[https://www.pythonforthelab.com/blog/learning-not-to-handle-exceptions/|Learning (Not) to Handle Exceptions]]
===== argparse =====
* [[https://mkaz.blog/working-with-python/argparse|Python Argparse Cookbook]]
===== Matplotlib =====
==== lmodern mit T1-Encoding ====
Um mit matplotlib PDF-Dateien mit der Schriftart lmodern und korrektem T1-Encoding zu erstellen (zum Beispiel für richtig kopierbare Umlaute) muss [[latex|LaTeX]] anstelle des internen Mechanismus von matplotlib verwendet werden. Dazu sind folgende Einstellung notwendig:
plt.rcParams['text.latex.preamble']=[r"\usepackage{lmodern} \usepackage[T1]{fontenc}"]
params = {
'text.usetex' : True,
'text.latex.unicode': True,
'font.family' : "lmodern"
}
plt.rcParams.update(params)
Das Setzen von ''\usepackage{lmodern}'' vor den anderen Optionen ist notwendig, siehe http://stackoverflow.com/a/18633695
\\ Der Textsatz mit [[latex|LaTeX]] ist deutlich langsamer als der interne Mechanismus von matplotlib.
[[latex|LaTeX]] wird nicht im aktuellen Arbeitsverzeichnis ausgeführt, sondern im Cache-Verzeichnis (''~/.cache/matplotlib'' unter Linux oder über ''get_cachedir()'' herausfinden).
Deshalb funktioniert ''\input'' mit relativen Pfaden nicht.
Die TeX-Dateien verbleiben im Cache-Verzeichnis und können zum Debugging nützlich sein.
==== "Unknown Font" in Python 3 ====
Wird eine Grafik mit matplotlib unter Python 3 als PDF exportiert, werden die Fonts im PDF mit ''pdffonts'' oder PDF-Viewern wie [[okular|Okular]] u.U. als "unknown font" angezeigt.
Dabei handelt es sich um diesen [[https://github.com/matplotlib/matplotlib/issues/3049|Bug]].
Abhilfe:
* Python 2 verwenden oder
* eine aktuelle matplotlib-Version verwenden
==== Achsenbeschriftung in wissenschaftlicher Schreibweise ====
Mit der Funktion [[http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.ticklabel_format|ticklabel_format]] kann die Achsenbeschriftung in wissenschaftlicher Schreibweise gesetzt werden.
mpl.ticklabel_format(style='sci', scilimits=(-3,4), axis='both')
Die Defaultwerte für ''scilimits'' werden in ''rcParams'' durch ''axes.formatter.limits'' gesetzt.
==== Nur Ganzzahlen als Achsenbeschriftung ====
Der einfachste Weg nur Ganzzahlen als "Ticks" auf den Achsen anzuzeigen, ist dieser:
from matplotlib.ticker import MaxNLocator
ax = plt.figure().gca()
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
==== Ränder beim Autoscaling ====
Um zu verhindern, dass die Datenpunkte nicht mehr auf den Achsen liegen und daher schlecht zu erkennen sind, gibt es zwei Möglichkeiten. Entweder kann in der ''matplotlibrc'' folgendes gesetzt werden:
axes.xmargin : 0.1
axes.ymargin : 0.1
Dies wirkt dann für alle Plots. Um jeden Plot individuell zu ändern:
plt.plot(t,np.sin(t))
plt.margins(x=0.1, y=0.1)
Der angegebene Werte kann jeweils zwischen 0 und 1 liegen.
Innerhalb von Subplots müssen die Ränder für jede Achse separat gesetzt werden, ''plt.margins()'' wirkt nur auf die letzte:
for ax in axes:
ax.margins(x=0.1, y=0.1)
==== Links ====
* [[http://emptypipes.org/2013/11/09/matplotlib-multicategory-barchart/|Creating a Grouped Bar Chart in Matplotlib]]
===== Configobj =====
configobj ist eine Klasse mit der Konfigurationsdateien einfach geparst und die geparsten Werte valididert werden können.
==== Validierung der Argumente ====
Mit dem ''validator''-Objekt können die Argumente gegen eine Spezifikation ("configspec") geprüft und in den entsprechenden Typ umgewandelt werden, hier eine [[https://configobj.readthedocs.io/en/latest/validate.html#the-standard-functions|Liste der möglichen Argumenttypen]].
Die in der configspec angegebenen Typen werden nicht geprüft.
Tippfehler (z.B. ''bool'' vs. ''boolean'') werden daher nicht erkannt und der Typ des Arguments bleibt unverändert.
=== Validierung von Listen mit nur einem Argument ===
Gibt man in der configspec zur Validierung ''string_list'' an und enthält die zugewiesene Liste nur ein Element, wird der String in eine Liste von Buchstaben zerlegt.
Benötigt man eine Liste mit einem Element muss die Zuweisung mit einem Komma am Ende erfolgen:
testvar = "teststring",
Alternative kann die configspec auf ''force_list'' geändert werden.
Dabei wird allerdings keine Typprüfung vorgenommen.
==== Schriftgröße der Legende ====
Die einfachste Art die Schriftgröße der Legende zu verändern ist diese:
plot.legend(prop={'size':6})
==== Tick-Frequenz ändern ====
Um den Abstand der Ticks manuell zu setzen, kann der ''MultipleLocator'' verwendet werden.
Als Argument bekommt er den Abstand der Ticks.
import matplotlib.ticker as ticker
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
==== Links ====
* [[https://web.archive.org/web/20201109033721/http://www.voidspace.org.uk/python/articles/configobj.shtml|An Introduction to ConfigObj (Webarchive)]]
===== csv =====
==== Zeilenende ====
Standardmäßig wird beim Schreiben das Windowszeilenende ''\r\n'' benutzt.
Um dies zu ändern, kann der ''lineterminator'' explizit gesetzt werden:
writer = csv.writer(f, lineterminator='\n')
===== setuptools =====
==== Vergleichen von Versionsnummern ====
Mit der Funktion ''parse_version'' lassen sich komfortabel auch komplizierte Versionsnummern vergleichen:
from pkg_resources import parse_version
if parse_version('2.1-rc2') < parse_version('2.1'):
print "Version is to low!"
Die Version von Python-Modulen lässt sich über die [[https://www.python.org/dev/peps/pep-0396/|__version__-Eigenschaft]] herausfinden:
import scipy
print scipy.__version__
===== numpy =====
==== alle Inf in Array durch Null ersetzen ====
Alle INFs in einem Numpy-Array lassen sich wie folgt durch Null oder einen beliebigen anderen Wert ersetzen:
from numpy import inf
x = numpy.array([-inf, -inf, 37.49668579])
x[x == inf] = 0
===== UTF-8 =====
Python 3 unterstützt UTF-8 gut und komfortabel.
In Python 2 muss das Encoding eines Sourcefiles
mit
# -*- coding: utf-8 -*-
oder
# coding: utf8
explizit gesetzt werden und Strings müssen das Präfix
''u'' bekommen:
some_string = u'ÜÖÄ'
* [[https://docs.python.org/3/howto/unicode.html|Unicode How-To]]
===== Tipps & Tricks =====
==== Prüfen, ob String numerisch ====
Um zu prüfen, ob ein String numerisch ist, ist es häufig nicht sinnvoll, die Funktionen ''isdigit()'' oder ''isnumeric()'' (nur für Unicodestrings definiert) zu verwenden, da diese keine negativen Zahlen akzeptieren.
Als Alternative kann man sowas verwenden:
def isnumeric(value)
try:
val = float(value)
return True
except ValueError:
return False
===== Links =====
* [[https://www.python.org/|Python Homepage]]
* [[regular_expressions#python|RegExps mit Python]]
* [[http://bit.ly/unipain|Pragmatic Unicode or How do I stop the pain]]
* [[http://python-3-patterns-idioms-test.readthedocs.io|Python 3 Patterns, Recipes and Idioms]] noch unfertiges Open-Source-Buch