7. Eingabe und Ausgabe

Es gibt verschiedene Möglichkeiten, die Ausgabe eines Programms darzustellen; Daten können in einer für Menschen lesbaren Form ausgegeben oder zur späteren Verwendung in eine Datei geschrieben werden. In diesem Kapitel werden einige dieser Möglichkeiten behandelt.

7.1. Erweiterte Formatierungsmöglichkeiten für die Ausgabe

Bisher haben wir zwei Möglichkeiten kennengelernt, Werte zu schreiben: Ausdrucksanweisungen und die Funktion print(). (Eine dritte Möglichkeit ist die Verwendung der Methode write() von Datei-Objekten. Auf die Standardausgabedatei kann als sys.stdout verwiesen werden. Weitere Informationen hierzu findest du in der Bibliotheksreferenz.)

Oftmals möchtest du mehr Kontrolle über die Formatierung Ihrer Ausgabe haben, als nur durch Leerzeichen getrennte Werte auszugeben. Es gibt verschiedene Möglichkeiten, die Ausgabe zu formatieren.

  • Um formatierte Zeichenfolgenliterale zu verwenden, beginne eine Zeichenfolge mit f oder F vor dem öffnenden Anführungszeichen oder dem dreifachen Anführungszeichen. Innerhalb dieser Zeichenfolge kannst du einen Python-Ausdruck zwischen den Zeichen { und } schreiben, der sich auf Variablen oder Literalwerte beziehen kann.

    >>> year = 2016
    >>> event = 'Referendum'
    >>> f'Ergebnisse des {year} {event} '
    'Ergebnisse des Referendums von 2016'
    
  • Die Methode str.format() für Zeichenketten erfordert mehr manuellen Aufwand. Verwende weiterhin { und }, um zu kennzeichnen, an welcher Stelle eine Variable eingefügt werden soll, und können detaillierte Formatierungsanweisungen angeben, müssen jedoch zusätzlich die zu formatierenden Informationen bereitstellen. Im folgenden Codeblock findest du zwei Beispiele für die Formatierung von Variablen:

    >>> yes_votes = 42_572_654
    >>> total_votes = 85_705_149
    >>> prozent = Ja-Stimmen / Gesamtstimmen
    >>> '{:-9} Ja-Stimmen  {:2,2 %}'.format(Ja-Stimmen, prozent)
    ' 42.572.654 Ja-Stimmen  49,67 %'
    

    Beachte, dass die yes_votes nur bei negativen Zahlen mit Leerzeichen und einem Minuszeichen aufgefüllt werden. Das Beispiel gibt außerdem percentage multipliziert mit 100 aus, mit zwei Dezimalstellen und einem Prozentzeichen am Ende (weitere Informationen findest du unter Formatspezifikation Mini-Sprache ).

  • Schließlich kannst du die gesamte Zeichenfolgenbearbeitung selbst übernehmen, indem du Zeichenfolgenausschnitte und Verkettungsoperationen nutzen tust, um jedes erdenkliche Layout zu erstellen. Der Typ „Zeichenfolge“ verfügt über einige Methoden, mit denen sich Zeichenfolgen auf eine bestimmte Spaltenbreite auffüllen lassen.

Wenn du keine aufwendige Ausgabe benötigst, sondern lediglich eine schnelle Anzeige einiger Variablen zu Debugging-Zwecken wünschen, kannst du jeden Wert mit den Funktionen repr() oder str() in eine Zeichenkette umwandeln.

Die Funktion str() soll Darstellungen von Werten zurückgeben, die für Menschen gut lesbar sind, während repr() dazu dient, Darstellungen zu generieren, die vom Interpreter gelesen werden können (oder einen SyntaxError auslösen, falls keine entsprechende Syntax vorhanden ist). Bei Objekten, für die es keine spezielle Darstellung für Menschen gibt, gibt str() denselben Wert zurück wie repr(). Viele Werte, wie beispielsweise Zahlen oder Strukturen wie Listen und Wörterbücher, werden von beiden Funktionen auf dieselbe Weise dargestellt. Insbesondere Zeichenketten haben zwei unterschiedliche Darstellungen.

Einige Beispiele:

>>> s = 'Hallo, Welt.'
>>> str(s)
'Hallo, Welt.'
>>> repr(s)
"'Hallo, Welt.'"
>>> str(1/7)
'0,14285714285714285'
>>> x = 10 * 3,25
>>> y = 200 * 200
>>> s = 'Der Wert von x ist ' + repr(x) + ', und y ist ' + repr(y) + '...'
>>> print(s)
Der Wert von x ist 32,5 und der von y ist 40000...
>>> # Die Funktion repr() fügt bei einer Zeichenkette Anführungszeichen und Backslashes hinzu:
>>> hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # Das Argument für repr() kann ein beliebiges Python-Objekt sein:
>>> repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"

The string module contains a Template class that offers yet another way to substitute values into strings, using placeholders like $x and replacing them with values from a dictionary, but offers much less control of the formatting.

7.1.1. Formatierte Zeichenfolgenliterale

Mit formatierten String-Literalen (kurz auch als f-Strings bezeichnet) kannst du den Wert von Python-Ausdrücken in einen String einfügen, indem du dem String die Präfixe f oder F voranstellen und Ausdrücke in der Form {expression} schreibst.

Dem Ausdruck kann ein optionaler Formatbezeichner folgen. Dies ermöglicht eine genauere Steuerung der Formatierung des Werts. Im folgenden Beispiel wird Pi auf drei Stellen nach dem Komma gerundet:

>>> import math
>>> print(f'Der Wert von Pi beträgt ungefähr {math.pi:.3f}.')
Der Wert von Pi beträgt ungefähr 3,142.

Wird nach dem Befehl ':' eine Ganzzahl übergeben, wird die Breite dieses Feldes auf die angegebene Mindestanzahl an Zeichen festgelegt. Dies ist nützlich, um Spalten auszurichten.

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print(f'{name:10} ==> {phone:10d}')
...
Sjoerd     ==>       4127
Jack       ==>       4098
Dcab       ==>       7678

Es können weitere Modifikatoren verwendet werden, um den Wert vor der Formatierung umzuwandeln. '!a' wendet ascii() an, '!s' wendet str() an und '!r' wendet repr() an

>>> animals = 'Aale'
>>> print(f'Mein Luftkissenfahrzeug ist voll mit {animals}.')
Mein Luftkissenfahrzeug ist voll mit Aalen.
>>> print(f'Mein Luftkissenfahrzeug ist voll mit {animals!r}.')
Mein Luftkissenfahrzeug ist voll mit 'Aalen'.

Mit dem Bezeichner = lässt sich ein Ausdruck so erweitern, dass er zunächst den Text des Ausdrucks, dann ein Gleichheitszeichen und anschließend die Darstellung des ausgewerteten Ausdrucks enthält:

>>> bugs = 'roaches'
>>> count = 13
>>> area = 'living room'
>>> print(f'Debugging {bugs=} {count=} {area=}')
Debugging bugs='roaches' count=13 area='living room'

Weitere Informationen zum Spezifizierer = findest du unter selbstdokumentierende Ausdrücke. Eine Übersicht über diese Formatvorgaben findest du im Referenzhandbuch unter Formatspezifikation Mini-Sprache.

7.1.2. Die String-Methode format()

Die grundlegende Verwendung der Methode str.format() sieht wie folgt aus:

>>> print('Wir sind die {}, die "{}!" sagen'.format('Ritter', 'Ni'))
Wir sind die Ritter, die "Ni!" sagen

Die Klammern und die darin enthaltenen Zeichen (sogenannte Formatfelder) werden durch die an die Methode str.format() übergebenen Objekte ersetzt. Eine Zahl in den Klammern kann verwendet werden, um auf die Position des an die Methode str.format() übergebenen Objekts zu verweisen.

>>> print('{0} und {1}'.format('Spam', 'Eier'))
Spam und Eier
>>> print('{1} und {0}'.format('Spam', 'Eier'))
Eier und Spam

Werden in der Methode str.format() Schlüsselwortargumente verwendet, wird auf deren Werte über den Namen des Arguments verwiesen.

>>> print('Diese {food} lautet {adjective}.'.format(
...       food='Spam', adjective='absolut schrecklich'))
Dieser Spam ist absolut schrecklich.

Positions- und Schlüsselwortargumente können beliebig kombiniert werden:

>>> print('Die Geschichte von {0}, {1} und {other}.'.format('Bill', 'Manfred',
...                                                    other='Georg'))
Die Geschichte von Bill, Manfred und Georg.

Wenn du eine wirklich lange Formatzeichenfolge hast, die du nicht aufteilen möchtest, wäre es praktisch, wenn du die zu formatierenden Variablen nicht anhand ihrer Position, sondern anhand ihres Namens referenzieren könntest. Dies lässt sich erreichen, indem du einfach das Wörterbuch übergibst und eckige Klammern '[]' verwendest, um auf die Schlüssel zuzugreifen.

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
...       'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Dies könnte auch erreicht werden, indem das Wörterbuch table als Schlüsselwortargumente mit der Notation ** übergeben wird.

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Dies ist besonders nützlich in Kombination mit der integrierten Funktion vars(), die ein Wörterbuch zurückgibt, das alle lokalen Variablen enthält:

>>> table = {k: str(v) for k, v in vars().items()}
>>> message = " ".join([f'{k}: ' + '{' + k + '};' for k in table.keys()])
>>> print(message.format(**table))
__name__: __main__; __doc__: None; __package__: None; __loader__: ...

Die folgenden Zeilen erzeugen beispielsweise eine übersichtlich ausgerichtete Spaltenreihe, in der Ganzzahlen sowie deren Quadrate und Kubikzahlen aufgeführt sind:

>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

Einen vollständigen Überblick über die Zeichenfolgenformatierung mit str.format() findest du unter Syntax für Formatzeichenketten.

7.1.3. Manuelle Formatierung von Zeichenfolgen

Hier ist dieselbe Tabelle mit Quadraten und Würfeln, die manuell formatiert wurde:

>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # Beachte die Verwendung von 'end' in der vorherigen Zeile
...     print(repr(x*x*x).rjust(4))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

(Beachte, dass das einzelne Leerzeichen zwischen den einzelnen Spalten durch die Funktionsweise von print() hinzugefügt wurde: Diese Funktion fügt immer Leerzeichen zwischen ihren Argumenten ein.)

Die Methode str.rjust() von String-Objekten richtet eine Zeichenkette in einem Feld mit einer bestimmten Breite rechtsbündig aus, indem sie links mit Leerzeichen aufgefüllt wird. Es gibt ähnliche Methoden: str.ljust() und str.center(). Diese Methoden schreiben nichts, sondern geben lediglich eine neue Zeichenkette zurück. Ist die Eingabezeichenkette zu lang, wird sie nicht gekürzt, sondern unverändert zurückgegeben; dies bringt zwar das Spaltenlayout durcheinander, ist aber in der Regel besser als die Alternative, bei der ein Wert falsch dargestellt würde. (Wenn du wirklich eine Kürzung wünschst, kannst du jederzeit eine Slice-Operation hinzufügen, wie in x.ljust(n)[:n] beschrieben.)

Es gibt noch eine weitere Methode, str.zfill(), die eine numerische Zeichenkette links mit Nullen auffüllt. Sie erkennt Plus- und Minuszeichen:

>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003,14'
>>> '3,14159265359'.zfill(5)
'3,14159265359'

7.1.4. Alte Zeichenfolgenformatierung

Der %-Operator (Modulo) kann auch zur Formatierung von Zeichenketten verwendet werden. Bei der Angabe von format % values (wobei format eine Zeichenkette ist) werden die Konvertierungsspezifikationen % in format durch null oder mehr Elemente aus values ersetzt. Dieser Vorgang wird allgemein als Zeichenketteninterpolation bezeichnet. Zum Beispiel:

>>> import math
>>> print('Der Wert von Pi beträgt ungefähr %5.3f.' % math.pi)
Der Wert von Pi beträgt ungefähr 3,142.

Weitere Informationen findest du im Abschnitt String-Formatierung im printf-Stil.

7.2. Dateien lesen und schreiben

open() gibt ein Dateiobjekt zurück und wird meist mit zwei Positionsargumenten und einem Schlüsselwortargument verwendet: open(filename, mode, encoding=None)

>>> f = open('workfile', 'w', encoding="utf-8")

Das erste Argument ist eine Zeichenkette, die den Dateinamen enthält. Das zweite Argument ist eine weitere Zeichenkette, die einige Zeichen enthält, die beschreiben, wie die Datei verwendet wird. mode kann 'r' lauten, wenn die Datei nur gelesen wird, 'w' für das reine Schreiben (eine bereits vorhandene Datei mit demselben Namen wird dabei gelöscht) und 'a' öffnet die Datei zum Anhängen; alle in die Datei geschriebenen Daten werden automatisch am Ende angehängt. 'r+' öffnet die Datei sowohl zum Lesen als auch zum Schreiben. Das Argument mode ist optional; wird es weggelassen, wird 'r' angenommen.

Normalerweise werden Dateien im Textmodus geöffnet, das heißt, du liest Zeichenketten aus der Datei aus und schreibst Zeichenketten in die Datei, die in einer bestimmten Kodierung kodiert sind. Wenn keine Kodierung angegeben ist, ist die Standardeinstellung plattformabhängig (siehe open()). Da UTF-8 der moderne De-facto-Standard ist, wird encoding="utf-8" empfohlen, es sei denn, du weisst, dass du eine andere Kodierung verwenden musst. Durch Hinzufügen eines 'b' zum Modus wird die Datei im Binärmodus geöffnet. Daten im Binärmodus werden als bytes -Objekte gelesen und geschrieben. Beim Öffnen einer Datei im Binärmodus kannst du keine Kodierung angeben.

Im Textmodus werden beim Lesen standardmäßig plattformspezifische Zeilenenden (\n unter Unix, \r\n unter Windows) in \n umgewandelt. Beim Schreiben im Textmodus werden \n standardmäßig wieder in plattformspezifische Zeilenenden umgewandelt. Diese im Hintergrund vorgenommene Änderung der Dateidaten ist für Textdateien unbedenklich, führt jedoch bei Binärdateien wie den in den Formaten JPEG oder EXE zu Datenverlusten. Achte daher unbedingt darauf, beim Lesen und Schreiben solcher Dateien den Binärmodus zu verwenden.

Es hat sich bewährt, beim Umgang mit Datei-Objekten das Schlüsselwort with zu verwenden. Der Vorteil besteht darin, dass die Datei nach Abschluss der Suite ordnungsgemäß geschlossen wird, selbst wenn an irgendeiner Stelle eine Ausnahme ausgelöst wird. Die Verwendung von with ist zudem wesentlich kürzer als das Schreiben der entsprechenden try-finally-Blöcke:

>>> with open('workfile', encoding="utf-8") as f:
...     read_data = f.read()

>>> # Wir können überprüfen, ob die Datei automatisch geschlossen wurde.
>>> f.closed
True

Wenn du das Schlüsselwort with nicht verwendest, solltest du die Funktion f.close() aufrufen, um die Datei zu schließen und die von ihr belegten Systemressourcen sofort freizugeben.

Warnung

Der Aufruf von f.write() ohne das Schlüsselwort with ` oder der Aufruf von f.close() kann dazu führen, dass die Argumente von f.write() nicht vollständig auf die Festplatte geschrieben werden, selbst wenn das Programm erfolgreich beendet wird.

Nachdem ein Dateiobjekt geschlossen wurde – entweder durch eine with-Anweisung oder durch den Aufruf von f.close()– schlagen alle Versuche, das Dateiobjekt zu verwenden, automatisch fehl.

>>> f.close()
>>> f.read()
Traceback (letzter Aufruf zuletzt):
  Datei "<stdin>", Zeile 1, in <module>
ValueError: E/A-Vorgang an einer geschlossenen Datei.

7.2.1. Methoden von Datei-Objekten

In den übrigen Beispielen dieses Abschnitts wird davon ausgegangen, dass bereits ein Dateiobjekt namens f angelegt wurde.

Um den Inhalt einer Datei zu lesen, rufe f.read(size) auf. Diese Funktion liest eine bestimmte Datenmenge ein und gibt sie als Zeichenkette (im Textmodus) oder als Byte-Objekt (im Binärmodus) zurück. size ist ein optionales numerisches Argument. Wenn size weggelassen wird oder negativ ist, wird der gesamte Inhalt der Datei gelesen und zurückgegeben; es ist Ihr Problem, wenn die Datei doppelt so groß ist wie der Arbeitsspeicher Ihres Rechners. Andernfalls werden höchstens size Zeichen (im Textmodus) oder size Bytes (im Binärmodus) gelesen und zurückgegeben. Wenn das Ende der Datei erreicht wurde, gibt f.read() eine leere Zeichenkette zurück ('').

>>> f.read()
'Das ist der gesamte Inhalt der Datei.\n'
>>> f.read()
''

f.readline() Liest eine einzelne Zeile aus der Datei; am Ende der Zeichenkette wird ein Zeilenumbruchzeichen (\n) belassen, das nur in der letzten Zeile der Datei weggelassen wird, wenn die Datei nicht mit einem Zeilenumbruch endet. Dadurch ist der Rückgabewert eindeutig: Wenn f.readline() eine leere Zeichenkette zurückgibt, ist das Ende der Datei erreicht, während eine Leerzeile durch '\n' dargestellt wird, eine Zeichenkette, die nur ein einziges Zeilenendezeichen enthält.

>>> f.readline()
'Dies ist die erste Zeile der Datei.\n'
>>> f.readline()
'Zweite Zeile der Datei\n'
>>> f.readline()
''

Um Zeilen aus einer Datei zu lesen, kannst du das Dateiobjekt in einer Schleife durchlaufen. Dies ist speichereffizient, schnell und führt zu einfachem Code:

>>> for line in f:
...     print(line, end='')
...
Dies ist die erste Zeile der Datei.
Zweite Zeile der Datei

Wenn du alle Zeilen einer Datei in eine Liste einlesen möchtest, kannst du auch list(f) oder f.readlines() verwenden.

f.write(string) Schreibt den Inhalt von string in die Datei und gibt die Anzahl der geschriebenen Zeichen zurück.

>>> f.write('Das ist ein Test\n')
15

Andere Objekttypen müssen vor dem Schreiben konvertiert werden – entweder in eine Zeichenkette (im Textmodus) oder in ein Byte-Objekt (im Binärmodus):

>>> value = ('die Antwort', 42)
>>> s = str(value)  # das Tupel in eine Zeichenkette umwandeln
>>> f.write(s)
18

f.tell() Gibt eine Ganzzahl zurück, die die aktuelle Position des Dateiobjekts in der Datei angibt – im Binärmodus als Anzahl der Bytes ab dem Dateianfang und im Textmodus als undurchsichtige Zahl.

Um die Position des Dateiobjekts zu ändern, verwende f.seek(offset, whence). Die Position wird berechnet, indem offset zu einem Referenzpunkt addiert wird; der Referenzpunkt wird durch das Argument whence festgelegt. Ein whence-Wert von 0 misst vom Anfang der Datei aus, 1 verwendet die aktuelle Dateiposition und 2 verwendet das Ende der Datei als Bezugspunkt. whence kann weggelassen werden und ist standardmäßig auf 0 gesetzt, wobei der Anfang der Datei als Bezugspunkt verwendet wird.

>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)      # Zum 6. Byte in der Datei springen
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2)  # Zum dritten Byte vor dem Ende springen
13
>>> f.read(1)
b'd'

In Textdateien (die ohne b in der Moduszeichenfolge geöffnet wurden) sind nur relative Sprünge zum Dateianfang zulässig (mit Ausnahme des Sprungs zum Dateiende mit seek(0, 2)), und die einzigen gültigen offset-Werte sind diejenigen, die von f.tell() zurückgegeben werden, oder Null. Jeder andere offset-Wert führt zu undefiniertem Verhalten.

Dateiobjekte verfügen über einige zusätzliche Methoden, wie beispielsweise isatty() und truncate(), die jedoch seltener verwendet werden; eine vollständige Anleitung zu Dateiobjekten findest du in der Bibliotheksreferenz.

7.2.2. Strukturierte Daten speichern mit json

Zeichenketten lassen sich problemlos in eine Datei schreiben und aus einer Datei lesen. Bei Zahlen ist der Aufwand etwas größer, da die Methode read() nur Zeichenketten zurückgibt, die an eine Funktion wie int() übergeben werden müssen, die eine Zeichenkette wie '123' entgegennimmt und deren numerischen Wert 123 zurückgibt. Wenn du komplexere Datentypen wie verschachtelte Listen und Wörterbücher speichern möchtest, wird das manuelle Parsen und Serialisieren kompliziert.

Anstatt dass Benutzer ständig Code schreiben und debuggen müssen, um komplizierte Datentypen in Dateien zu speichern, ermöglicht Python die Verwendung des beliebten Datenaustauschformats namens JSON (JavaScript Object Notation). Das Standardmodul namens json kann Python-Datenhierarchien übernehmen und in Zeichenfolgen-Darstellungen umwandeln; dieser Vorgang wird als Serialisierung bezeichnet. Das Rekonstruieren der Daten aus der Zeichenfolgenrepräsentation wird als Deserialisierung bezeichnet. Zwischen der Serialisierung und der Deserialisierung kann die das Objekt repräsentierende Zeichenfolge in einer Datei oder einem Datenspeicher abgelegt oder über eine Netzwerkverbindung an einen entfernten Rechner gesendet worden sein.

Bemerkung

Das JSON-Format wird häufig von modernen Anwendungen für den Datenaustausch verwendet. Viele Programmierer sind bereits damit vertraut, was es zu einer guten Wahl für die Interoperabilität macht.

Wenn du ein Objekt vom Typ x hast, kannst du dessen JSON-Zeichenkettendarstellung mit einer einzigen Codezeile anzeigen:

>>> import json
>>> x = [1, 'simple', 'list']
>>> json.dumps(x)
'[1, "simple", "list"]'

Eine weitere Variante der Funktion dumps(), die den Namen dump() trägt, serialisiert das Objekt einfach in eine Textdatei. Wenn also f ein zum Schreiben geöffnetes Textdatei-Objekt ist, können wir Folgendes tun:

json.dump(x, f)

Um das Objekt erneut zu dekodieren, wenn f ein Binärdatei- oder Textdatei-Objekt ist, das zum Lesen geöffnet wurde:

x = json.load(f)

Bemerkung

JSON-Dateien müssen in UTF-8 kodiert sein. Verwende die Option encoding="utf-8", wenn du eine JSON-Datei als Textdatei öffnest, sowohl beim Lesen als auch beim Schreiben.

Diese einfache Serialisierungstechnik eignet sich für Listen und Wörterbücher, doch die Serialisierung beliebiger Klasseninstanzen in JSON erfordert etwas mehr Aufwand. Die Dokumentation zum Modul json enthält eine Erläuterung dazu.

Siehe auch

pickle - das Pickle-Modul

Im Gegensatz zu JSON ist pickle ein Protokoll, das die Serialisierung beliebig komplexer Python-Objekte ermöglicht. Als solches ist es Python-spezifisch und kann nicht zur Kommunikation mit Anwendungen verwendet werden, die in anderen Sprachen geschrieben sind. Außerdem ist es standardmäßig unsicher: Die Deserialisierung von pickle-Daten aus einer nicht vertrauenswürdigen Quelle kann zur Ausführung von beliebigem Code führen, wenn die Daten von einem erfahrenen Angreifer manipuliert wurden.