Schlagwort-Archive: python

Die Tupel-Fallgrube

Was viele nicht wissen, ist dass bei der Deklarierung eines Python Tupels die runden Klammern eigentlich nicht zum syntaktischen Konstrukt gehören, sondern nur zur optischen Abgrenzung verwendet werden. Dies bedeutet folgendes:

Eingabe:

x = (1, 2, 3)
print(x)

Ausgabe:

(1, 2, 3)

Doch ebenso:

Eingabe:

x = 1, 2, 3
print(x)

Ausgabe:

(1, 2, 3)

Dies erscheint erst einmal nicht schlimm, oder sogar vielleicht elegant, da man sich Tipparbeit sparen kann, doch diese quasi Inkonsistenz in der Syntax kann zu schwierig zu findenden Fehlern führen, wie z.B. folgendem:

Eingabe:

x = min(1, 2, 3),
print(x)

man beachte das “,” hinter dem call von min(). Dies führt dann hierzu:

Ausgabe:

(1,)

also einem Tupel, obwohl man einen Integer-Wert erwartet. Ein solcher Bug kann schwer zu finden bzw. zu erkennen sein.
Deshalb ergibt type hinting auch bei Python Sinn.

Dictionaries und shallow copies in Python

Wenn man mit dictonaries in python arbeitet sollte man das Konzept der shallow copy kennen, da dieses Feature zu fiesen und vielleicht schwer zu findenden bugs führen kann. Mit der Funktion copy() kann man von einem Dictionary eine Kopie, aber eben “nur” eine shallow copy erzeugen.

Bei einer shallow copy handelt es sich zwar um zwei separate Objekte, aber die einzelnen Elemente der beiden Dictionaries verweisen auf dieselbe Speicherstelle. Diesen Umstand stellt folgender Beispielcode dar:

# Dictionaries definieren:
my_dict: dict[int, list[str]] = {0: ["a", "b"], 1: ["c", "d"]}
dict_copy: dict[int, list[str]] = my_dict.copy()

# ids der Dictionaries ausgeben:
print(id(my_dict))
print(id(dict_copy))

# Inhalte der beiden Dictionaries ausgeben
print(my_dict)
print(dict_copy)

Ausgabe:

2513461433280
2513483301312
{0: ['a', 'b'], 1: ['c', 'd']}
{0: ['a', 'b'], 1: ['c', 'd']}

Wir sehen anhand der unterschiedlichen IDs der Objekte, dass es sich in der Tat um zwei unterschiedliche Objekte handelt, die aber den gleichen Inhalt haben.

# Bei der Kopie des Dictionaries das erste Item des ersten Dictionary-Eintrags verändern
dict_copy[0][0] = "test"

# Erneut die Inhalte der beiden Dictionaries ausgeben:
print(my_dict)
print(dict_copy)

Ausgabe:

{0: ['test', 'b'], 1: ['c', 'd']}
{0: ['test', 'b'], 1: ['c', 'd']}

Wie wir sehen, wurde nicht nur die Kopie des Dictionaries (dict_copy) verändert, sondern auch das ursprüngliche Dictionary. Dies verdeutlicht, dass die Items im Objekt Verweise auf dieselbe Stelle im Speicher sind. Es ist also Vorsicht geboten, wenn man mit copy() arbeitet und dann einzelne Items der Dictionaries manipuliert.

Vektorisierte Operationen mit Pandas

Aktuell beschäftige ich mich intensiv mit Python im Kontext von Data Science.
Hierbei kommt man natürlich nicht an Pandas vorbei. Und natürlich gibt es, wie so gut bei jedem Problem, welches man durch Programmcode lösen möchte, mehrere Wege zum Ziel.

Bei der Verwendung von Pandas Dataframes könnte man auf die Idee kommen, folgenden Code zu schreiben, um alle Werte einer Spalte zu verarbeiten und das Ergebnis in eine neue Spalte zu schreiben:

df['wert_quadrat'] = df.apply(lambda row: row['wert'] ** 2, axis=1)

Der Code quadriert den Wert in der Spalte “wert” und erzeugt dann eine neue Spalte “wert_quadrat” mit dem Ergebnis.
Dies funktioniert, doch es gibt eine elegantere und vor allem performantere Lösung: vektorisierte Operationen!

Hier die gleiche Operation als vektorisierte Operation:

df['wert_quadrat'] = row['wert'] ** 2

Je nach Größe des Datensatzes kann man hierdurch erhebliche Performancegewinne erzielen, da bei vektorisierten Operationen kein Python-Loop durchgeführt wird, bei dem für jede Zeile die entsprechende Python-Funktion ausgeführt wird, sondern die Operation wird an die zugrundeliegende numpy arrays deligiert, welche die Operation in Maschinencode ausführt.

pylint – ‘Unable to import’ – import-error

Wenn man mit VScode Python entwickelt und für das linting pylint verwendet, dann kann es vorkommen, dass der Editor die Imports als falsch bzw. nicht aufgelöst anzeigt und dies mit der Einblendung:

Unable to import {Modulname} pylint(import-error)

quittiert. Dies liegt daran, dass pylint nicht den korrekt Python-Interpreter bzw. den Pfad dorthin kennt.

Lösung: Man öffnet das VScode Menü mit F1 bzw. Strg + Shift + P und wählt über die Option Python: Select Interpreter den korrekten Python-Interpreter aus.