Dies ist die zweite Sammlung von Python-Tipps und -Programmierungen aus meinem
@ pythonetc-Feed . Vorherige Auswahl:
Reguläre Sprachen
Eine reguläre Sprache ist eine formale Sprache, die als
endliche Zustandsmaschine dargestellt werden kann . Mit anderen Worten, für die zeichenweise Textverarbeitung müssen Sie sich nur den aktuellen Status merken, und die Anzahl solcher Status ist endlich.
Ein perfektes Beispiel: Eine Maschine, die prüft, ob die Eingabe eine Primzahl wie –3, 2.2 oder 001 ist. Am Anfang des Artikels wird eine endliche Zustandsmaschine angezeigt. Doppelkreise zeigen den Endzustand an, in dem die Maschine anhalten kann.
Die Maschine startet von Position . Vielleicht findet es ein Minus, dann eine Ziffer und verarbeitet dann an Position ③ die erforderliche Anzahl von Ziffern. Danach kann das Dezimaltrennzeichen (③ → ④) überprüft werden, gefolgt von einer Ziffer (④ → ⑤) oder mehr (⑤ → ⑤).
Ein klassisches Beispiel für eine unregelmäßige Sprache ist eine Familie von Zeichenfolgenausdrücken der Form:
ab
aaa-bbb
aaaaa-bbbbb
Formal benötigen wir eine Zeichenfolge mit N Instanzen von
a
, dann
–
, dann - N Instanzen von
b
, wobei N eine ganze Zahl größer als 0 ist. Sie können dies nicht mit einer Zustandsmaschine implementieren, da Sie sich die Anzahl der Zeichen merken müssen, die Sie für möglich gehalten haben Dies geschieht nur mit einer unendlichen Anzahl von Zuständen.
Reguläre Ausdrücke können nur reguläre Sprachen angeben. Stellen Sie vor der Verwendung sicher, dass Ihre Zeichenfolge sogar mit einer Zustandsmaschine verarbeitet werden kann. Sie eignen sich beispielsweise nicht zum Verarbeiten von JSON-, XML- oder sogar arithmetischen Ausdrücken in Klammern.
Es ist lustig, dass viele moderne Regex-Motoren nicht regelmäßig sind. Beispielsweise unterstützt das Regex-Modul für Python die Rekursion (was bei der Lösung des Problems mit
aaa-bbb
hilfreich ist ).
Dynamische Planung
Wenn Python einen Methodenaufruf ausführt, z. B.
af(b, c, d)
, muss es zuerst die richtige Funktion
f
auswählen. Aufgrund des Polymorphismus bestimmt a, was letztendlich gewählt wird. Der Prozess der Auswahl einer Methode wird üblicherweise als dynamischer Versand bezeichnet.
Python unterstützt nur Single-Dispatch-Polymorphismus. Dies bedeutet, dass nur das Objekt selbst die Auswahl des Objekts beeinflusst (in unserem Beispiel
a
). In anderen Sprachen können die Typen
b
,
c
und
d
berücksichtigt werden - ein solcher Mechanismus wird als Mehrfachversand bezeichnet. Ein markantes Beispiel ist die C # -Sprache.
Es kann jedoch eine Mehrfachplanung mit einer einzigen emuliert werden. Aus diesem Grund wurde die Besucherentwurfsvorlage erstellt: Sie verwendet zweimal einen einzelnen Versand, um einen doppelten Versand zu simulieren.
Denken Sie daran, dass Überladungsmethoden (wie in Java und C ++) kein Analogon zum Mehrfachversand sind. Das dynamische Dispatching funktioniert zur Laufzeit, und das Überladen wird nur während der Kompilierung durchgeführt.
Diese Beispiele helfen Ihnen, das Thema besser zu verstehen:
Inline-Namen
In Python können Sie problemlos alle Standardvariablen ändern, die im globalen Bereich verfügbar sind:
>>> print = 42 >>> print(42) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable
Dies ist nützlich, wenn Ihr Modul Funktionen definiert, deren Namen mit den Namen der integrierten Funktionen übereinstimmen. Dies geschieht auch in Situationen, in denen Sie die Metaprogrammierung üben und einen beliebigen Zeichenfolgenwert als Bezeichner verwenden.
Aber selbst wenn Sie die Namen einiger integrierter Funktionen duplizieren, benötigen Sie möglicherweise Zugriff auf das, worauf sie sich ursprünglich bezogen haben. Deshalb gibt es das eingebaute Modul:
>>> import builtins >>> print = 42 >>> builtins.print(1) 1
Auch in den meisten Modulen ist die Variable
__builtins__
verfügbar. Aber es gibt einen Trick. Erstens ist dies eine Funktion der cpython-Implementierung und sollte normalerweise überhaupt nicht verwendet werden. Zweitens kann sich
builtins
sowohl auf
builtins
als auch auf
builtins.__dict__
, je nachdem, wie das aktuelle Modul geladen wurde.
strace
Manchmal verhält sich die Anwendung im Kampf seltsam. Anstatt es neu zu starten, möchten Sie möglicherweise die Ursache der Probleme verstehen, solange dies möglich ist.
Die naheliegende Lösung besteht darin, die Aktionen des Programms zu analysieren und zu verstehen, welcher Teil des Codes ausgeführt wird. Die ordnungsgemäße Protokollierung erleichtert diese Aufgabe, aber Ihre Protokolle sind möglicherweise aufgrund der Architektur oder der in den Einstellungen ausgewählten Protokollierungsstufe nicht detailliert genug.
In solchen Fällen kann Strace nützlich sein. Dies ist ein Unix-Dienstprogramm, das Systemaufrufe verfolgt. Sie können es zuvor
strace python script.py
-
strace python script.py
-, aber es ist normalerweise bequemer, eine Verbindung zu einer bereits ausgeführten Anwendung
strace -p PID
:
strace -p PID
.
$ cat test.py with open('/tmp/test', 'w') as f: f.write('test') $ strace python test.py 2>&1 | grep open | tail -n 1 open("/tmp/test", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3
Jede Zeile der Ablaufverfolgung enthält den Namen des Systemaufrufs, die Argumente in Klammern und den Rückgabewert. Da einige Argumente verwendet werden, um das Ergebnis eines Systemaufrufs zurückzugeben und keine Daten an diesen zu übergeben, kann die Zeilenausgabe angehalten werden, bis der Systemaufruf endet.
In diesem Beispiel wird die Ausgabe gestoppt, bis das Schreiben in STDIN abgeschlossen ist:
$ strace python -c 'input()' read(0,
Tupelliterale
Einer der inkonsistentesten Teile der Python-Syntax sind Tupelliterale.
Um ein Tupel zu erstellen, reicht es aus, die durch Kommas getrennten Werte aufzulisten:
1, 2, 3
. Was ist mit einem Einzelelement-Tupel? Fügen Sie einfach ein hängendes Komma hinzu:
1,
,. Es sieht hässlich aus und führt oft zu Fehlern, ist aber ziemlich logisch.
Wie wäre es mit einem leeren Tupel? Dies ist ein Komma -? Nein, das ist
()
. Und was, Klammern erzeugen ein Tupel wie Kommas? Nein,
(4)
ist kein Tupel, es ist nur
4
.
In : a = [ ...: (1, 2, 3), ...: (1, 2), ...: (1), ...: (), ...: ] In : [type(x) for x in a] Out: [tuple, tuple, int, tuple]
Um die Dinge noch schwieriger zu verwirren, erfordern Tupelliterale häufig zusätzliche Klammern. Wenn Sie das Tupel als einziges Argument für die Funktion benötigen, funktioniert
f(1, 2, 3)
offensichtlich nicht - Sie müssen
f((1, 2, 3))
schreiben.