Python Language
Häufige Fehler
Suche…
Einführung
Python ist eine Sprache, die klar und lesbar sein soll, ohne Unklarheiten und unerwartete Verhaltensweisen. Leider sind diese Ziele nicht in allen Fällen erreichbar. Aus diesem Grund gibt es in Python einige Eckpunkte, in denen es möglicherweise etwas anderes tut als erwartet.
In diesem Abschnitt werden einige Probleme beschrieben, die beim Schreiben von Python-Code auftreten können.
Ändern Sie die Reihenfolge, die Sie durchlaufen
Eine for
Schleife durchläuft eine Sequenz, daher kann das Ändern dieser Sequenz innerhalb der Schleife zu unerwarteten Ergebnissen führen (insbesondere beim Hinzufügen oder Entfernen von Elementen):
alist = [0, 1, 2]
for index, value in enumerate(alist):
alist.pop(index)
print(alist)
# Out: [1]
Hinweis: Mit list.pop()
werden Elemente aus der Liste entfernt.
Das zweite Element wurde nicht gelöscht, da die Iteration der Reihe nach die Indizes durchläuft. Die obige Schleife wiederholt sich zweimal mit folgenden Ergebnissen:
# Iteration #1
index = 0
alist = [0, 1, 2]
alist.pop(0) # removes '0'
# Iteration #2
index = 1
alist = [1, 2]
alist.pop(1) # removes '2'
# loop terminates, but alist is not empty:
alist = [1]
Dieses Problem tritt auf, weil sich die Indizes ändern, während sie sich in Richtung des Indexanstiegs ändern. Um dieses Problem zu vermeiden, können Sie die Schleife rückwärts durchlaufen :
alist = [1,2,3,4,5,6,7]
for index, item in reversed(list(enumerate(alist))):
# delete all even items
if item % 2 == 0:
alist.pop(index)
print(alist)
# Out: [1, 3, 5, 7]
Wenn Sie die Schleife am Ende durchlaufen und Elemente entfernen (oder hinzufügen), hat dies keinen Einfluss auf die Indexe der Elemente, die sich zuvor in der Liste befanden. In diesem Beispiel werden also alle Elemente, die auch von alist
stammen, alist
.
Ein ähnliches Problem entsteht beim Einfügen oder Anhängen von Elementen an eine Liste, die Sie durchlaufen , was zu einer Endlosschleife führen kann:
alist = [0, 1, 2]
for index, value in enumerate(alist):
# break to avoid infinite loop:
if index == 20:
break
alist.insert(index, 'a')
print(alist)
# Out (abbreviated): ['a', 'a', ..., 'a', 'a', 0, 1, 2]
Ohne die break
fügt die Schleife 'a'
solange dem Computer nicht genügend Speicher zur Verfügung steht und das Programm weiterlaufen darf. In einer Situation wie dieser wird normalerweise bevorzugt, eine neue Liste zu erstellen und der neuen Liste Elemente hinzuzufügen, während Sie die ursprüngliche Liste durchlaufen.
Bei Verwendung einer for
Schleife können Sie die Listenelemente nicht mit der Platzhaltervariablen ändern :
alist = [1,2,3,4]
for item in alist:
if item % 2 == 0:
item = 'even'
print(alist)
# Out: [1,2,3,4]
Im obigen Beispiel ändert das Ändern eines item
nichts an der ursprünglichen Liste . Sie müssen den alist[2]
( alist[2]
) verwenden, und enumerate()
funktioniert dafür gut:
alist = [1,2,3,4]
for index, item in enumerate(alist):
if item % 2 == 0:
alist[index] = 'even'
print(alist)
# Out: [1, 'even', 3, 'even']
Eine while
Schleife ist in manchen Fällen die bessere Wahl:
Wenn Sie alle Elemente in der Liste löschen möchten :
zlist = [0, 1, 2]
while zlist:
print(zlist[0])
zlist.pop(0)
print('After: zlist =', zlist)
# Out: 0
# 1
# 2
# After: zlist = []
Wenn Sie zlist
einfach zurücksetzen, zlist
dasselbe Ergebnis.
zlist = []
Das obige Beispiel kann auch mit len()
kombiniert werden, um nach einem bestimmten Punkt zu stoppen oder um alle Elemente außer x
zu löschen:
zlist = [0, 1, 2]
x = 1
while len(zlist) > x:
print(zlist[0])
zlist.pop(0)
print('After: zlist =', zlist)
# Out: 0
# 1
# After: zlist = [2]
Oder zum Durchlaufen einer Liste, während Elemente gelöscht werden, die eine bestimmte Bedingung erfüllen (in diesem Fall werden alle geraden Elemente gelöscht):
zlist = [1,2,3,4,5]
i = 0
while i < len(zlist):
if zlist[i] % 2 == 0:
zlist.pop(i)
else:
i += 1
print(zlist)
# Out: [1, 3, 5]
Beachten Sie, dass Sie i
nicht erhöhen, nachdem Sie ein Element gelöscht haben. Durch das Löschen des Elements in zlist[i]
hat sich der Index des nächsten Elements um eins verringert. zlist[i]
mit demselben Wert für i
bei der nächsten Iteration überprüfen, werden Sie das nächste Element in der Liste korrekt überprüfen .
Ein anderer Weg, über das Entfernen unerwünschter Elemente aus einer Liste nachzudenken, besteht darin , gewünschte Elemente zu einer neuen Liste hinzuzufügen . Das folgende Beispiel ist eine Alternative zu diesem Beispiel while
Schleife:
zlist = [1,2,3,4,5]
z_temp = []
for item in zlist:
if item % 2 != 0:
z_temp.append(item)
zlist = z_temp
print(zlist)
# Out: [1, 3, 5]
Hier führen wir die gewünschten Ergebnisse in eine neue Liste ein. Die temporäre Liste kann dann optional der ursprünglichen Variablen zugewiesen werden.
Mit diesem Gedankengang können Sie eine der elegantesten und leistungsstärksten Funktionen von Python aufrufen, Listenverständnisse , die temporäre Listen eliminieren und von der zuvor diskutierten In-Place-Liste / Index-Mutationsideologie abweichen.
zlist = [1,2,3,4,5]
[item for item in zlist if item % 2 != 0]
# Out: [1, 3, 5]
Veränderliches Standardargument
def foo(li=[]):
li.append(1)
print(li)
foo([2])
# Out: [2, 1]
foo([3])
# Out: [3, 1]
Dieser Code verhält sich wie erwartet, aber was ist, wenn wir kein Argument übergeben?
foo()
# Out: [1] As expected...
foo()
# Out: [1, 1] Not as expected...
Dies liegt daran, dass Standardargumente von Funktionen und Methoden nicht zur Laufzeit, sondern zur Definitionszeit ausgewertet werden. Also nur wir jemals eine einzige Instanz der haben li
Liste.
Um dies zu umgehen, verwenden Sie nur unveränderliche Typen für Standardargumente:
def foo(li=None):
if not li:
li = []
li.append(1)
print(li)
foo()
# Out: [1]
foo()
# Out: [1]
Eine Verbesserung und if not li
korrekt als False
ausgewertet, gilt dies für viele andere Objekte, z. Die folgenden Beispielargumente können zu unbeabsichtigten Ergebnissen führen:
x = []
foo(li=x)
# Out: [1]
foo(li="")
# Out: [1]
foo(li=0)
# Out: [1]
Der idiomatische Ansatz besteht darin, das Argument direkt gegen das None
Objekt zu prüfen:
def foo(li=None):
if li is None:
li = []
li.append(1)
print(li)
foo()
# Out: [1]
Listenmultiplikation und gemeinsame Referenzen
Betrachten Sie den Fall der Erstellung einer verschachtelten Listenstruktur durch Multiplikation:
li = [[]] * 3
print(li)
# Out: [[], [], []]
Auf den ersten Blick denken wir, wir hätten eine Liste mit 3 verschachtelten Listen. Versuchen wir, 1
an die erste anzuhängen:
li[0].append(1)
print(li)
# Out: [[1], [1], [1]]
1
wurde auf alle Listen in den beigefügten li
.
Der Grund ist, dass [[]] * 3
keine list
mit 3 verschiedenen list
. Vielmehr erstellt er eine list
mit mindestens 3 Verweise auf die gleiche list
Objekt. Wenn wir also an li[0]
anhängen, ist die Änderung in allen Unterelementen von li
sichtbar. Dies ist gleichbedeutend mit:
li = []
element = [[]]
li = element + element + element
print(li)
# Out: [[], [], []]
element.append(1)
print(li)
# Out: [[1], [1], [1]]
Dies kann weiter bestätigt werden, wenn wir die Speicheradressen der enthaltenen list
mit id
ausdrucken:
li = [[]] * 3
print([id(inner_list) for inner_list in li])
# Out: [6830760, 6830760, 6830760]
Die Lösung besteht darin, die inneren Listen mit einer Schleife zu erstellen:
li = [[] for _ in range(3)]
Anstatt eine einzige list
erstellen und anschließend drei Verweise darauf zu erstellen, erstellen wir nun drei unterschiedliche Listen. Dies kann wiederum mit der id
Funktion überprüft werden:
print([id(inner_list) for inner_list in li])
# Out: [6331048, 6331528, 6331488]
Sie können das auch tun. Es bewirkt, dass bei jedem append
Aufruf eine neue leere Liste erstellt wird.
>>> li = []
>>> li.append([])
>>> li.append([])
>>> li.append([])
>>> for k in li: print(id(k))
...
4315469256
4315564552
4315564808
Verwenden Sie den Index nicht, um eine Sequenz zu durchlaufen.
Nicht:
for i in range(len(tab)):
print(tab[i])
Tun :
for elem in tab:
print(elem)
for
wird die meisten Iterationsvorgänge für Sie automatisieren.
Verwenden Sie Aufzählung, wenn Sie wirklich sowohl den Index als auch das Element benötigen .
for i, elem in enumerate(tab):
print((i, elem))
Seien Sie vorsichtig, wenn Sie "==" verwenden, um nach "Wahr" oder "Falsch" zu suchen
if (var == True):
# this will execute if var is True or 1, 1.0, 1L
if (var != True):
# this will execute if var is neither True nor 1
if (var == False):
# this will execute if var is False or 0 (or 0.0, 0L, 0j)
if (var == None):
# only execute if var is None
if var:
# execute if var is a non-empty string/list/dictionary/tuple, non-0, etc
if not var:
# execute if var is "", {}, [], (), 0, None, etc.
if var is True:
# only execute if var is boolean True, not 1
if var is False:
# only execute if var is boolean False, not 0
if var is None:
# same as var == None
Überprüfen Sie nicht, ob Sie dies tun können, und führen Sie den Fehler aus
Pythonistas sagen normalerweise "Es ist einfacher, um Vergebung zu bitten als um Erlaubnis".
Nicht:
if os.path.isfile(file_path):
file = open(file_path)
else:
# do something
Tun:
try:
file = open(file_path)
except OSError as e:
# do something
Oder noch besser mit Python 2.6+
:
with open(file_path) as file:
Es ist viel besser, weil es viel generischer ist. Sie können try/except
auf fast alles anwenden. Sie müssen sich nicht darum kümmern, was zu tun ist, um dies zu verhindern, sondern nur den Fehler, den Sie riskieren.
Nicht gegen Typ prüfen
Python ist dynamisch typisiert. Wenn Sie also nach Typ suchen, verlieren Sie die Flexibilität. Verwenden Sie stattdessen das Eingeben von Enten, indem Sie das Verhalten überprüfen. Wenn Sie eine Zeichenfolge in einer Funktion erwarten, konvertieren Sie ein Objekt mit str()
in eine Zeichenfolge. Wenn Sie mit einer Liste rechnen, verwenden Sie list()
, um alle Iterierbaren in eine Liste zu konvertieren.
Nicht:
def foo(name):
if isinstance(name, str):
print(name.lower())
def bar(listing):
if isinstance(listing, list):
listing.extend((1, 2, 3))
return ", ".join(listing)
Tun:
def foo(name) :
print(str(name).lower())
def bar(listing) :
l = list(listing)
l.extend((1, 2, 3))
return ", ".join(l)
Auf die letzte Weise akzeptiert foo
jedes Objekt. bar
akzeptiert Strings, Tupel, Sets, Listen und vieles mehr. Billig TROCKEN.
Mischen Sie keine Leerzeichen und Tabulatoren
Objekt als erstes übergeordnetes Objekt verwenden
Das ist knifflig, aber es wird Sie beißen, wenn Ihr Programm wächst. In Python 2.x
gibt es alte und neue Klassen. Die Alten sind gut, alt. Sie verfügen nicht über einige Funktionen und können bei der Vererbung unangenehm sein. Um nutzbar zu sein, muss jede Ihrer Klassen den "neuen Stil" haben. Dazu machen Sie es vom object
erben.
Nicht:
class Father:
pass
class Child(Father):
pass
Tun:
class Father(object):
pass
class Child(Father):
pass
In Python 3.x
alle Klassen einen neuen Stil, so dass Sie dies nicht tun müssen.
Initialisieren Sie Klassenattribute nicht außerhalb der init- Methode
Menschen, die aus anderen Sprachen kommen, finden es verlockend, weil Sie dies in Java oder PHP tun. Sie schreiben den Klassennamen, listen Ihre Attribute auf und geben ihnen einen Standardwert. Es scheint in Python zu funktionieren, aber das funktioniert nicht so, wie Sie denken. Dadurch werden Klassenattribute (statische Attribute) eingerichtet. Wenn Sie versuchen, das Objektattribut abzurufen, erhalten Sie dessen Wert, wenn es nicht leer ist. In diesem Fall werden die Klassenattribute zurückgegeben. Daraus ergeben sich zwei große Gefahren:
Wenn das Klassenattribut geändert wird, wird der Anfangswert geändert.
Wenn Sie ein veränderbares Objekt als Standardwert festlegen, wird dasselbe Objekt für alle Instanzen gemeinsam verwendet.
Nicht (es sei denn, Sie möchten statisch):
class Car(object):
color = "red"
wheels = [Wheel(), Wheel(), Wheel(), Wheel()]
Tun :
class Car(object):
def __init__(self):
self.color = "red"
self.wheels = [Wheel(), Wheel(), Wheel(), Wheel()]
Integer- und String-Identität
Python verwendet internes Caching für eine Reihe von ganzen Zahlen, um den unnötigen Aufwand durch wiederholtes Erstellen zu reduzieren.
Dies kann zu einem verwirrenden Verhalten beim Vergleich von Integer-Identitäten führen:
>>> -8 is (-7 - 1)
False
>>> -3 is (-2 - 1)
True
und mit einem anderen Beispiel:
>>> (255 + 1) is (255 + 1)
True
>>> (256 + 1) is (256 + 1)
False
Warte was?
Wir können sehen , dass die Identität Betrieb is
Ausbeuten True
für einige ganze Zahlen ( -3
, 256
) , aber nicht für andere ( -8
, 257
).
Genauer gesagt, Ganzzahlen im Bereich [-5, 256]
werden beim Start des Interpreters intern zwischengespeichert und nur einmal erstellt. Als solche sind sie identisch und mit ihrer Identität zu vergleichen is
ergibt True
; Ganzzahlen außerhalb dieses Bereichs werden (normalerweise) on-the-fly erstellt und ihre Identitäten werden mit False
verglichen.
Dies ist eine häufige Fallstricke, da dies ein üblicher Bereich für Tests ist, aber oft genug versagt der Code beim späteren Bereitstellungsprozess (oder schlechterer Produktion), ohne dass ein offensichtlicher Grund vorliegt, nachdem er in der Entwicklung perfekt gearbeitet hat.
Die Lösung besteht darin , Werte immer mit dem Gleichheitsoperator ( ==
) und nicht mit dem Identitätsoperator ( is
) zu vergleichen.
Python hält auch Strings häufig verwendete Verweise auf und in ähnlicher Weise verwirrende Verhalten führen können , wenn Identitäten zu vergleichen (dh unter Verwendung is
) von Strings.
>>> 'python' is 'py' + 'thon'
True
Die Zeichenfolge 'python'
wird häufig verwendet, daher hat Python ein Objekt, das alle Verweise auf die Zeichenfolge 'python'
verwenden.
Bei ungewöhnlichen Zeichenfolgen schlägt der Vergleich der Identität fehl, selbst wenn die Zeichenfolgen gleich sind.
>>> 'this is not a common string' is 'this is not' + ' a common string'
False
>>> 'this is not a common string' == 'this is not' + ' a common string'
True
Vergleichen Sie die Zeichenfolgenwerte wie bei der Ganzzahl immer mit dem Gleichheitsoperator ( ==
) und nicht mit dem Identitätsoperator ( is
).
Zugriff auf Attribute von Int-Literalen
Sie haben vielleicht gehört, dass alles in Python ein Objekt ist, sogar Literale. Dies bedeutet beispielsweise, dass 7
ein Objekt ist, das heißt, es hat Attribute. Eines dieser Attribute ist beispielsweise die bit_length
. Es gibt die Menge an Bits zurück, die zur Darstellung des Werts benötigt wird, für den er aufgerufen wird.
x = 7
x.bit_length()
# Out: 3
Wenn Sie sehen, dass der obige Code funktioniert, könnten Sie intuitiv denken, dass 7.bit_length()
funktionieren würde, nur um herauszufinden, dass dies einen SyntaxError
. Warum? weil der Interpreter zwischen einem Attributzugriff und einer Floating-Nummer unterscheiden muss (z. B. 7.2
oder 7.bit_length()
). Das kann nicht, und deshalb wird eine Ausnahme ausgelöst.
Es gibt verschiedene Möglichkeiten, auf die Attribute eines int
Literalen zuzugreifen:
# parenthesis
(7).bit_length()
# a space
7 .bit_length()
Die Verwendung von zwei Punkten (wie 7..bit_length()
) funktioniert in diesem Fall nicht, da dadurch ein float
Literal erstellt wird und Floats nicht über die bit_length()
-Methode verfügen.
Dieses Problem besteht nicht beim Zugriff auf float
Attribute der float
Literale, da der Interperter "intelligent" genug ist, um zu wissen, dass ein float
Literal nicht zwei enthalten kann .
, zum Beispiel:
7.2.as_integer_ratio()
# Out: (8106479329266893, 1125899906842624)
Verkettung oder Operator
Beim Testen auf einen von mehreren Gleichheitsvergleichen:
if a == 3 or b == 3 or c == 3:
es ist verlockend, dies zu verkürzen
if a or b or c == 3: # Wrong
Das ist falsch; Der Operator or
hat eine niedrigere Priorität als ==
. Der Ausdruck wird also wie if (a) or (b) or (c == 3):
Der richtige Weg ist die explizite Überprüfung aller Bedingungen:
if a == 3 or b == 3 or c == 3: # Right Way
Alternativ kann die eingebaute any()
Funktion anstelle von verketteten or
Operatoren verwendet werden:
if any([a == 3, b == 3, c == 3]): # Right
Oder, um es effizienter zu machen:
if any(x == 3 for x in (a, b, c)): # Right
Oder um es kürzer zu machen:
if 3 in (a, b, c): # Right
Hier verwenden wir die in
Operator zu testen , ob der Wert in einem Tupel vorhanden ist , die Werte enthalten , die wir gegen vergleichen wollen.
Ebenso ist es falsch zu schreiben
if a == 1 or 2 or 3:
was sollte als geschrieben werden
if a in (1, 2, 3):
sys.argv [0] ist der Name der ausgeführten Datei
Das erste Element von sys.argv[0]
ist der Name der gerade ausgeführten Python-Datei. Die restlichen Elemente sind die Skriptargumente.
# script.py
import sys
print(sys.argv[0])
print(sys.argv)
$ python script.py
=> script.py
=> ['script.py']
$ python script.py fizz
=> script.py
=> ['script.py', 'fizz']
$ python script.py fizz buzz
=> script.py
=> ['script.py', 'fizz', 'buzz']
Wörterbücher sind nicht geordnet
Sie können erwarten, dass ein Python-Wörterbuch nach Schlüsseln sortiert wird, z. B. einer C ++ std::map
. Dies ist jedoch nicht der Fall:
myDict = {'first': 1, 'second': 2, 'third': 3}
print(myDict)
# Out: {'first': 1, 'second': 2, 'third': 3}
print([k for k in myDict])
# Out: ['second', 'third', 'first']
Python hat keine eingebaute Klasse, die ihre Elemente automatisch nach Schlüssel sortiert.
Wenn das Sortieren jedoch kein Muss ist und Sie möchten, dass sich das Wörterbuch nur an die Reihenfolge der Einfügung der Schlüssel / Wert-Paare erinnert, können Sie collections.OrderedDict
verwenden. collections.OrderedDict
:
from collections import OrderedDict
oDict = OrderedDict([('first', 1), ('second', 2), ('third', 3)])
print([k for k in oDict])
# Out: ['first', 'second', 'third']
OrderedDict
Sie, dass das Initialisieren eines OrderedDict
mit einem Standardwörterbuch das Wörterbuch in keiner Weise für Sie sortiert. Alles , was diese Struktur macht , ist die Reihenfolge der Schlüsseleinführungs zu bewahren.
Die Implementierung von Wörterbüchern wurde in Python 3.6 geändert , um den Speicherverbrauch zu verbessern. Ein Nebeneffekt dieser neuen Implementierung ist, dass auch die Reihenfolge der an eine Funktion übergebenen Schlüsselwortargumente beibehalten wird:
def func(**kw): print(kw.keys())
func(a=1, b=2, c=3, d=4, e=5)
dict_keys(['a', 'b', 'c', 'd', 'e']) # expected order
Caveat: Vorsicht , dass „die Reihenfolge erhaltender Aspekt dieser neuen Implementierung wird eine Implementierung Detail betrachtet und soll nicht als verlässlich angesehen werden“ , wie es in der Zukunft ändern kann.
Globale Interpreter-Sperre (GIL) und blockierende Threads
Über Pythons GIL wurde viel geschrieben . Dies kann manchmal zu Verwirrung führen, wenn Sie mit Multi-Threaded-Anwendungen (nicht zu verwechseln mit Multiprozess-Anwendungen) umgehen.
Hier ist ein Beispiel:
import math
from threading import Thread
def calc_fact(num):
math.factorial(num)
num = 600000
t = Thread(target=calc_fact, daemon=True, args=[num])
print("About to calculate: {}!".format(num))
t.start()
print("Calculating...")
t.join()
print("Calculated")
Sie würden erwarten, dass Calculating...
direkt nach dem Start des Threads ausgedruckt wird. Wir wollten, dass die Berechnung in einem neuen Thread durchgeführt wird! Tatsächlich sehen Sie, dass es gedruckt wird, nachdem die Berechnung abgeschlossen ist. math.factorial
liegt daran, dass der neue Thread auf einer C-Funktion ( math.factorial
) math.factorial
die die GIL während der math.factorial
sperrt.
Es gibt ein paar Möglichkeiten, dies zu umgehen. Die erste besteht darin, Ihre faktorielle Funktion in nativem Python zu implementieren. Dadurch kann der Haupt-Thread die Kontrolle übernehmen, während Sie sich in Ihrer Schleife befinden. Der Nachteil ist, dass diese Lösung viel langsamer ist, da wir die C-Funktion nicht mehr verwenden.
def calc_fact(num):
""" A slow version of factorial in native Python """
res = 1
while num >= 1:
res = res * num
num -= 1
return res
Sie können auch eine gewisse Zeit lang sleep
bevor Sie mit der Ausführung beginnen. Hinweis: Dies erlaubt Ihrem Programm nicht, die Berechnung innerhalb der C-Funktion zu unterbrechen, aber Ihr Hauptthread kann nach dem Spawn fortfahren, was Sie vielleicht erwarten.
def calc_fact(num):
sleep(0.001)
math.factorial(num)
Variables Durchsickern in Listenverständnissen und für Schleifen
Betrachten Sie das folgende Listenverständnis
i = 0
a = [i for i in range(3)]
print(i) # Outputs 2
Dies tritt nur in Python 2 auf, da das Listenverständnis die Schleifensteuerungsvariable in den umgebenden Geltungsbereich ( Quelle ) "leckt". Dieses Verhalten kann zu schwer zu findenden Fehlern führen und wurde in Python 3 behoben .
i = 0
a = [i for i in range(3)]
print(i) # Outputs 0
Ebenso haben for-Schleifen keinen privaten Gültigkeitsbereich für ihre Iterationsvariable
i = 0
for i in range(3):
pass
print(i) # Outputs 2
Diese Art von Verhalten tritt sowohl in Python 2 als auch in Python 3 auf.
Um Probleme mit undichten Variablen zu vermeiden, verwenden Sie neue Variablen in Listenverständnissen und für Schleifen.
Mehrfachrückgabe
Die Funktion xyz liefert zwei Werte a und b:
def xyz():
return a, b
Code, der xyz aufruft, speichert das Ergebnis in einer Variablen, vorausgesetzt, xyz gibt nur einen Wert zurück:
t = xyz()
Der Wert von t
ist eigentlich ein Tupel (a, b), sodass jede Aktion, die sich auf t
bezieht, vorausgesetzt, dass es sich nicht um ein Tupel handelt, tief im Code mit einem unerwarteten Fehler in Bezug auf Tupel fehlschlagen kann.
TypeError: Typ Tupel definiert keine ... Methode
Die Lösung wäre zu tun:
a, b = xyz()
Anfänger werden Schwierigkeiten haben, den Grund für diese Nachricht zu finden, indem sie nur die Tupel-Fehlermeldung lesen!
Pythonic JSON-Schlüssel
my_var = 'bla';
api_key = 'key';
...lots of code here...
params = {"language": "en", my_var: api_key}
Wenn Sie mit JavaScript vertraut sind, ist die Variablenbewertung in Python-Wörterbüchern nicht das, was Sie erwarten. Diese Anweisung in JavaScript würde das params
Objekt wie folgt ergeben:
{
"language": "en",
"my_var": "key"
}
In Python würde sich jedoch folgendes Wörterbuch ergeben:
{
"language": "en",
"bla": "key"
}
my_var
wird ausgewertet und sein Wert wird als Schlüssel verwendet.