Neues in Python 2.5¶
- Autor:
A.M. Kuchling
Dieser Artikel erklärt die neuen Funktionen in Python 2.5. Die endgültige Veröffentlichung von Python 2.5 ist für August 2006 geplant; PEP 356 beschreibt den geplanten Veröffentlichungsplan. Python 2.5 wurde am 19. September 2006 veröffentlicht.
Die Änderungen in Python 2.5 sind eine interessante Mischung aus Sprach- und Bibliotheksverbesserungen. Die Bibliotheksverbesserungen werden meiner Meinung nach für die Python-Benutzergemeinschaft wichtiger sein, da mehrere weit verbreitete Pakete hinzugefügt wurden. Neue Module umfassen ElementTree für die XML-Verarbeitung (xml.etree), das SQLite-Datenbankmodul (sqlite) und das ctypes-Modul zum Aufrufen von C-Funktionen.
Die Sprachänderungen sind von mittlerer Bedeutung. Einige angenehme neue Funktionen wurden hinzugefügt, aber die meisten davon sind keine Funktionen, die Sie jeden Tag verwenden werden. Bedingte Ausdrücke wurden endlich mit einer neuartigen Syntax in die Sprache aufgenommen; siehe Abschnitt PEP 308: Bedingte Ausdrücke. Die neue 'with'-Anweisung erleichtert das Schreiben von Bereinigungscode (Abschnitt PEP 343: Die ‘with’-Anweisung). Werte können nun an Generatoren übergeben werden (Abschnitt PEP 342: Neue Generatorfunktionen). Importe sind nun entweder absolut oder relativ sichtbar (Abschnitt PEP 328: Absolute und relative Importe). Einige Eckfälle der Ausnahmebehandlung werden besser behandelt (Abschnitt PEP 341: Vereinheitlichtes try/except/finally). All diese Verbesserungen sind lohnenswert, aber sie sind Verbesserungen an einer bestimmten Sprachfunktion nach der anderen; keine davon sind breite Modifikationen an Pythons Semantik.
Zusätzlich zu den Sprach- und Bibliotheksneuerungen wurden im gesamten Quellbaum weitere Verbesserungen und Fehlerbehebungen vorgenommen. Eine Suche in den SVN-Änderungsprotokollen ergab, dass zwischen Python 2.4 und 2.5 353 Patches angewendet und 458 Fehler behoben wurden. (Beide Zahlen sind wahrscheinlich Unterschätzungen.)
Dieser Artikel versucht nicht, eine vollständige Spezifikation der neuen Funktionen zu sein; stattdessen werden die Änderungen kurz mit hilfreichen Beispielen vorgestellt. Für vollständige Details sollten Sie immer die Dokumentation für Python 2.5 unter https://docs.pythonlang.de konsultieren. Wenn Sie die vollständige Implementierung und Designbegründung verstehen möchten, beziehen Sie sich auf die PEP für eine bestimmte neue Funktion.
Kommentare, Vorschläge und Fehlerberichte zu diesem Dokument sind willkommen; senden Sie diese bitte per E-Mail an den Autor oder eröffnen Sie einen Fehler im Python-Fehlerverfolgungssystem.
PEP 308: Bedingte Ausdrücke¶
Seit langem fordern die Leute eine Möglichkeit, bedingte Ausdrücke zu schreiben, d.h. Ausdrücke, die Wert A oder Wert B zurückgeben, je nachdem, ob ein boolescher Wert wahr oder falsch ist. Ein bedingter Ausdruck ermöglicht es Ihnen, eine einzelne Zuweisungsanweisung zu schreiben, die denselben Effekt hat wie die folgende
if condition:
x = true_value
else:
x = false_value
Es gab endlose, ermüdende Diskussionen über die Syntax sowohl auf python-dev als auch auf comp.lang.python. Es wurde sogar abgestimmt, und die Mehrheit der Wähler wünschte sich bedingte Ausdrücke in irgendeiner Form, aber es gab keine Syntax, die von einer klaren Mehrheit bevorzugt wurde. Kandidaten waren C's cond ? true_v : false_v, if cond then true_v else false_v und 16 weitere Variationen.
Guido van Rossum wählte schließlich eine überraschende Syntax
x = true_value if condition else false_value
Die Auswertung ist immer noch träge wie bei vorhandenen booleschen Ausdrücken, sodass die Reihenfolge der Auswertung etwas springt. Der Bedingungsausdruck in der Mitte wird zuerst ausgewertet, und der true_value-Ausdruck wird nur ausgewertet, wenn die Bedingung wahr war. Ebenso wird der false_value-Ausdruck nur ausgewertet, wenn die Bedingung falsch ist.
Diese Syntax mag seltsam und rückwärts erscheinen; warum steht die Bedingung in der Mitte des Ausdrucks und nicht vorne wie in C's c ? x : y? Die Entscheidung wurde überprüft, indem die neue Syntax auf die Module in der Standardbibliothek angewendet und gesehen wurde, wie der resultierende Code gelesen wurde. In vielen Fällen, in denen ein bedingter Ausdruck verwendet wird, scheint ein Wert der „Normalfall“ zu sein und ein Wert ein „Ausnahmefall“, der nur seltener verwendet wird, wenn die Bedingung nicht erfüllt ist. Die bedingte Syntax macht dieses Muster etwas deutlicher
contents = ((doc + '\n') if doc else '')
Ich lese die obige Aussage so, dass sie bedeutet: „Hier wird contents normalerweise mit dem Wert doc+'\n' zugewiesen; manchmal ist doc leer, in welchem Sonderfall ein leerer String zurückgegeben wird.“ Ich bezweifle, dass ich bedingte Ausdrücke sehr oft verwenden werde, bei denen es keinen klaren normalen und ungewöhnlichen Fall gibt.
Es gab einige Diskussionen darüber, ob die Sprache bedingte Ausdrücke mit Klammern umschließen sollte. Es wurde beschlossen, Klammern in der Grammatik der Python-Sprache nicht vorzuschreiben, aber aus Stilgründen halte ich es für angebracht, sie immer zu verwenden. Betrachten Sie diese beiden Anweisungen
# First version -- no parens
level = 1 if logging else 0
# Second version -- with parens
level = (1 if logging else 0)
In der ersten Version denke ich, dass die Augen eines Lesers die Anweisung in „level = 1“, „if logging“, „else 0“ gruppieren und denken könnten, dass die Bedingung entscheidet, ob die Zuweisung an level durchgeführt wird. Die zweite Version liest sich meiner Meinung nach besser, da sie klarstellt, dass die Zuweisung immer durchgeführt wird und die Wahl zwischen zwei Werten getroffen wird.
Ein weiterer Grund für die Aufnahme der Klammern: Einige seltsame Kombinationen von Listen-Comprehensions und Lambdas könnten wie falsche bedingte Ausdrücke aussehen. Siehe PEP 308 für einige Beispiele. Wenn Sie Ihre bedingten Ausdrücke in Klammern setzen, werden Sie diesem Fall nicht begegnen.
Siehe auch
- PEP 308 - Bedingte Ausdrücke
PEP geschrieben von Guido van Rossum und Raymond D. Hettinger; implementiert von Thomas Wouters.
PEP 309: Partielle Funktionsanwendung¶
Das Modul functools soll Werkzeuge für die funktionale Programmierung enthalten.
Ein nützliches Werkzeug in diesem Modul ist die Funktion partial(). Für in einem funktionalen Stil geschriebene Programme möchten Sie manchmal Varianten bestehender Funktionen erstellen, bei denen einige Parameter voreingestellt sind. Betrachten Sie eine Python-Funktion f(a, b, c); Sie könnten eine neue Funktion g(b, c) erstellen, die äquivalent zu f(1, b, c) wäre. Dies nennt man „partielle Funktionsanwendung“.
partial() nimmt die Argumente (function, arg1, arg2, ... kwarg1=value1, kwarg2=value2). Das resultierende Objekt ist aufrufbar, sodass Sie es einfach aufrufen können, um function mit den voreingestellten Argumenten aufzurufen.
Hier ist ein kleines, aber realistisches Beispiel
import functools
def log (message, subsystem):
"Write the contents of 'message' to the specified subsystem."
print '%s: %s' % (subsystem, message)
...
server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')
Hier ist ein weiteres Beispiel aus einem Programm, das PyGTK verwendet. Hier wird dynamisch ein kontextbezogenes Popup-Menü erstellt. Der für den Menüpunkt bereitgestellte Callback ist eine partiell angewendete Version der Methode open_item(), bei der das erste Argument bereitgestellt wurde.
...
class Application:
def open_item(self, path):
...
def init (self):
open_func = functools.partial(self.open_item, item_path)
popup_menu.append( ("Open", open_func, 1) )
Eine weitere Funktion im Modul functools ist die Funktion update_wrapper(wrapper, wrapped), die Ihnen hilft, gut funktionierende Dekoratoren zu schreiben. update_wrapper() kopiert den Namen, das Modul und das Docstring-Attribut auf eine Wrapper-Funktion, damit Tracebacks innerhalb der gewrappten Funktion leichter verständlich sind. Zum Beispiel könnten Sie schreiben
def my_decorator(f):
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
functools.update_wrapper(wrapper, f)
return wrapper
wraps() ist ein Dekorator, der innerhalb Ihrer eigenen Dekoratoren verwendet werden kann, um die Informationen der gewrappten Funktion zu kopieren. Eine alternative Version des vorherigen Beispiels wäre
def my_decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
return wrapper
Siehe auch
- PEP 309 - Partielle Funktionsanwendung
PEP vorgeschlagen und geschrieben von Peter Harris; implementiert von Hye-Shik Chang und Nick Coghlan, mit Anpassungen von Raymond Hettinger.
PEP 314: Metadaten für Python-Softwarepakete v1.1¶
Einige einfache Abhängigkeitsunterstützung wurde zu Distutils hinzugefügt. Die Funktion setup() hat jetzt die Schlüsselwortparameter requires, provides und obsoletes. Wenn Sie eine Quellverteilung mit dem Befehl sdist erstellen, werden die Abhängigkeitsinformationen in der Datei PKG-INFO aufgezeichnet.
Ein weiterer neuer Schlüsselwortparameter ist download_url, der auf eine URL für den Quellcode des Pakets gesetzt werden sollte. Das bedeutet, dass es jetzt möglich ist, einen Eintrag im Paketindex nachzuschlagen, die Abhängigkeiten eines Pakets zu ermitteln und die erforderlichen Pakete herunterzuladen.
VERSION = '1.0'
setup(name='PyPackage',
version=VERSION,
requires=['numarray', 'zlib (>=1.1.4)'],
obsoletes=['OldPackage']
download_url=('http://www.example.com/pypackage/dist/pkg-%s.tar.gz'
% VERSION),
)
Eine weitere neue Verbesserung des Python-Paketindex unter https://pypi.org ist die Speicherung von Quell- und Binärarchiven für ein Paket. Der neue Distutils-Befehl upload lädt ein Paket in das Repository hoch.
Bevor ein Paket hochgeladen werden kann, müssen Sie eine Distribution mit dem Distutils-Befehl sdist erstellen können. Sobald das funktioniert, können Sie python setup.py upload ausführen, um Ihr Paket dem PyPI-Archiv hinzuzufügen. Optional können Sie das Paket mit den Optionen --sign und --identity GPG-signieren.
Paket-Upload wurde von Martin von Löwis und Richard Jones implementiert.
Siehe auch
- PEP 314 - Metadaten für Python-Softwarepakete v1.1
PEP vorgeschlagen und geschrieben von A.M. Kuchling, Richard Jones und Fred Drake; implementiert von Richard Jones und Fred Drake.
PEP 328: Absolute und relative Importe¶
Der einfachere Teil von PEP 328 wurde in Python 2.4 implementiert: Klammern konnten nun verwendet werden, um die aus einem Modul importierten Namen mit der Anweisung from ... import ... zu umschließen, was den Import vieler verschiedener Namen erleichterte.
Der kompliziertere Teil wurde in Python 2.5 implementiert: Der Import eines Moduls kann als absoluter oder paketrelativer Import spezifiziert werden. Der Plan ist, in zukünftigen Python-Versionen absolute Importe zum Standard zu machen.
Nehmen wir an, Sie haben ein Paketverzeichnis wie dieses
pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py
Dies definiert ein Paket namens pkg, das die Untermodule pkg.main und pkg.string enthält.
Betrachten Sie den Code im Modul main.py. Was passiert, wenn es die Anweisung import string ausführt? In Python 2.4 und früher wird es zuerst im Verzeichnis des Pakets nach einem relativen Import suchen, pkg/string.py finden, den Inhalt dieser Datei als Modul pkg.string importieren, und dieses Modul wird an den Namen string im Namensraum des Moduls pkg.main gebunden.
Das ist in Ordnung, wenn pkg.string das war, was Sie wollten. Aber was, wenn Sie Pythons Standardmodul string wollten? Es gibt keine saubere Möglichkeit, pkg.string zu ignorieren und nach dem Standardmodul zu suchen; im Allgemeinen musste man den Inhalt von sys.modules überprüfen, was etwas unsauber ist. Holger Krekel's Paket py.std bietet eine sauberere Methode, um aus der Standardbibliothek zu importieren, import py; py.std.string.join(), aber dieses Paket ist nicht auf allen Python-Installationen verfügbar.
Das Lesen von Code, der von relativen Importen abhängt, ist ebenfalls weniger klar, da ein Leser verwirrt sein kann, welches Modul, string oder pkg.string, gemeint ist. Python-Benutzer haben bald gelernt, die Namen von Standardbibliotheksmodulen nicht in den Namen der Untermodule ihrer Pakete zu duplizieren, aber Sie können sich nicht davor schützen, dass der Name Ihres Untermoduls für ein neues Modul verwendet wird, das in einer zukünftigen Version von Python hinzugefügt wird.
In Python 2.5 können Sie das Verhalten von import mit der Direktive from __future__ import absolute_import auf absolute Importe umstellen. Dieses Verhalten bei absoluten Importen wird in einer zukünftigen Version (wahrscheinlich Python 2.7) zum Standard werden. Sobald absolute Importe der Standard sind, findet import string immer die Version der Standardbibliothek. Es wird empfohlen, dass Benutzer absolute Importe so weit wie möglich verwenden, daher ist es ratsam, in Ihrem Code mit from pkg import string zu beginnen.
Relative Importe sind weiterhin möglich, indem ein führender Punkt zum Modulnamen hinzugefügt wird, wenn die Form from ... import verwendet wird
# Import names from pkg.string
from .string import name1, name2
# Import pkg.string
from . import string
Dies importiert das Modul string relativ zum aktuellen Paket. In pkg.main importiert dies also name1 und name2 aus pkg.string. Zusätzliche führende Punkte führen den relativen Import ab dem Elternteil des aktuellen Pakets durch. Zum Beispiel kann Code im Modul A.B.C Folgendes tun:
from . import D # Imports A.B.D
from .. import E # Imports A.E
from ..F import G # Imports A.F.G
Führende Punkte können nicht mit der Form import modname der Importanweisung verwendet werden, nur mit der Form from ... import.
Siehe auch
- PEP 328 - Imports: Mehrzeilig und Absolut/Relativ
PEP geschrieben von Aahz; implementiert von Thomas Wouters.
- https://pylib.readthedocs.io/
Die py-Bibliothek von Holger Krekel, die das Paket
py.stdenthält.
PEP 338: Module als Skripte ausführen¶
Der in Python 2.4 hinzugefügte Schalter -m zum Ausführen eines Moduls als Skript hat einige weitere Fähigkeiten erhalten. Anstatt in C-Code innerhalb des Python-Interpreters implementiert zu werden, verwendet der Schalter jetzt eine Implementierung in einem neuen Modul, runpy.
Das Modul runpy implementiert einen ausgefeilteren Importmechanismus, sodass es nun möglich ist, Module in einem Paket wie pychecker.checker auszuführen. Das Modul unterstützt auch alternative Importmechanismen wie das Modul zipimport. Das bedeutet, Sie können den Pfad eines .zip-Archivs zu sys.path hinzufügen und dann den Schalter -m verwenden, um Code aus dem Archiv auszuführen.
Siehe auch
- PEP 338 - Module als Skripte ausführen
PEP geschrieben und implementiert von Nick Coghlan.
PEP 341: Vereinheitlichtes try/except/finally¶
Bis Python 2.5 gab es die try-Anweisung in zwei Varianten. Sie konnten einen finally-Block verwenden, um sicherzustellen, dass Code immer ausgeführt wird, oder einen oder mehrere except-Blöcke, um bestimmte Ausnahmen abzufangen. Sie konnten keine except-Blöcke und einen finally-Block kombinieren, da die Erzeugung des richtigen Bytecodes für die kombinierte Version kompliziert war und es unklar war, was die Semantik der kombinierten Anweisung sein sollte.
Guido van Rossum verbrachte einige Zeit mit Java, das die Entsprechung der Kombination von except-Blöcken und einem finally-Block unterstützt, und dies klärte, was die Anweisung bedeuten sollte. In Python 2.5 können Sie nun Folgendes schreiben:
try:
block-1 ...
except Exception1:
handler-1 ...
except Exception2:
handler-2 ...
else:
else-block
finally:
final-block
Der Code in block-1 wird ausgeführt. Wenn der Code eine Ausnahme auslöst, werden die verschiedenen except-Blöcke getestet: Wenn die Ausnahme vom Typ Exception1 ist, wird handler-1 ausgeführt; andernfalls, wenn sie vom Typ Exception2 ist, wird handler-2 ausgeführt und so weiter. Wenn keine Ausnahme ausgelöst wird, wird else-block ausgeführt.
Unabhängig davon, was zuvor passiert ist, wird final-block ausgeführt, sobald der Codeblock abgeschlossen ist und alle ausgelösten Ausnahmen behandelt wurden. Selbst wenn ein Fehler in einem Ausnahmehandler oder im else-block auftritt und eine neue Ausnahme ausgelöst wird, wird der Code im final-block trotzdem ausgeführt.
Siehe auch
- PEP 341 - Vereinheitlichung von try-except und try-finally
PEP geschrieben von Georg Brandl; Implementierung durch Thomas Lee.
PEP 342: Neue Generatorfunktionen¶
Python 2.5 fügt eine einfache Möglichkeit hinzu, Werte *in* einen Generator zu übergeben. Wie in Python 2.3 eingeführt, produzieren Generatoren nur Ausgaben; sobald der Code eines Generators zur Erstellung eines Iterators aufgerufen wurde, gab es keine Möglichkeit, neue Informationen in die Funktion zu übergeben, wenn ihre Ausführung fortgesetzt wird. Manchmal wäre die Möglichkeit, einige Informationen zu übergeben, nützlich. Umständliche Lösungen dafür beinhalten, dass der Code des Generators eine globale Variable betrachtet und dann den Wert der globalen Variablen ändert oder ein veränderliches Objekt übergibt, das die Aufrufer dann modifizieren.
Um Ihre Erinnerung an grundlegende Generatoren aufzufrischen, hier ist ein einfaches Beispiel
def counter (maximum):
i = 0
while i < maximum:
yield i
i += 1
Wenn Sie counter(10) aufrufen, erhalten Sie einen Iterator, der die Werte von 0 bis 9 zurückgibt. Beim Anstoßen auf die yield-Anweisung gibt der Iterator den bereitgestellten Wert zurück und pausiert die Ausführung der Funktion, wobei die lokalen Variablen erhalten bleiben. Die Ausführung wird beim nächsten Aufruf der Methode next() des Iterators fortgesetzt und erfolgt nach der yield-Anweisung.
In Python 2.3 war yield eine Anweisung; sie gab keinen Wert zurück. In 2.5 ist yield nun ein Ausdruck, der einen Wert zurückgibt, der einer Variablen zugewiesen oder anderweitig verarbeitet werden kann
val = (yield i)
Ich empfehle Ihnen, einen yield-Ausdruck immer in Klammern zu setzen, wenn Sie etwas mit dem zurückgegebenen Wert tun, wie im obigen Beispiel. Die Klammern sind nicht immer notwendig, aber es ist einfacher, sie immer hinzuzufügen, anstatt sich daran erinnern zu müssen, wann sie benötigt werden.
(PEP 342 erklärt die genauen Regeln, nämlich dass ein yield-Ausdruck immer in Klammern gesetzt werden muss, es sei denn, er tritt als oberster Ausdruck auf der rechten Seite einer Zuweisung auf. Das bedeutet, Sie können val = yield i schreiben, müssen aber Klammern verwenden, wenn eine Operation stattfindet, wie in val = (yield i) + 12.)
Werte werden an einen Generator gesendet, indem dessen Methode send(value) aufgerufen wird. Der Code des Generators wird dann fortgesetzt und der yield-Ausdruck gibt den angegebenen value zurück. Wenn die reguläre Methode next() aufgerufen wird, gibt yield None zurück.
Hier ist das vorherige Beispiel, modifiziert, um die Änderung des internen Zählers zu ermöglichen.
def counter (maximum):
i = 0
while i < maximum:
val = (yield i)
# If value provided, change counter
if val is not None:
i = val
else:
i += 1
Und hier ist ein Beispiel zum Ändern des Zählers
>>> it = counter(10)
>>> print it.next()
0
>>> print it.next()
1
>>> print it.send(8)
8
>>> print it.next()
9
>>> print it.next()
Traceback (most recent call last):
File "t.py", line 15, in ?
print it.next()
StopIteration
yield gibt normalerweise None zurück, daher sollten Sie diesen Fall immer überprüfen. Verwenden Sie seinen Wert nicht einfach in Ausdrücken, es sei denn, Sie sind sicher, dass die Methode send() die einzige Methode ist, die zur Fortsetzung Ihrer Generatorfunktion verwendet wird.
Zusätzlich zu send() gibt es zwei weitere neue Methoden für Generatoren
throw(type, value=None, traceback=None)wird verwendet, um eine Ausnahme innerhalb des Generators auszulösen; die Ausnahme wird durch denyield-Ausdruck ausgelöst, wo die Ausführung des Generators pausiert ist.close()löst eine neue AusnahmeGeneratorExitinnerhalb des Generators aus, um die Iteration zu beenden. Bei Empfang dieser Ausnahme muss der Code des Generators entwederGeneratorExitoderStopIterationauslösen. Das Abfangen der AusnahmeGeneratorExitund das Zurückgeben eines Wertes ist illegal und löst eineRuntimeErroraus; wenn die Funktion eine andere Ausnahme auslöst, wird diese Ausnahme an den Aufrufer weitergegeben.close()wird auch vom Python-Garbage-Collector aufgerufen, wenn der Generator gesammelt wird.Wenn Sie Bereinigungscode ausführen müssen, wenn ein
GeneratorExitauftritt, empfehle ich die Verwendung einertry: ... finally:-Suite anstelle des Abfangens vonGeneratorExit.
Der kumulative Effekt dieser Änderungen ist, dass Generatoren von einseitigen Informationsproduzenten zu sowohl Produzenten als auch Konsumenten werden.
Generatoren werden auch zu *Koroutinen*, einer allgemeineren Form von Subroutinen. Subroutinen werden an einer Stelle eingegeben und an einer anderen Stelle verlassen (oben in der Funktion und einer return-Anweisung), aber Koroutinen können an vielen verschiedenen Stellen eingegeben, verlassen und fortgesetzt werden (die yield-Anweisungen). Wir müssen Muster für die effektive Nutzung von Koroutinen in Python herausfinden.
Die Hinzufügung der close()-Methode hat eine nicht offensichtliche Nebenwirkung. close() wird aufgerufen, wenn ein Generator von der Garbage Collection erfasst wird. Das bedeutet, dass der Code des Generators eine letzte Chance hat, ausgeführt zu werden, bevor der Generator zerstört wird. Diese letzte Chance bedeutet, dass try...finally-Anweisungen in Generatoren nun garantiert funktionieren; die finally-Klausel erhält nun immer eine Ausführungsmöglichkeit. Die syntaktische Beschränkung, dass man yield-Anweisungen nicht mit einer try...finally-Suite mischen konnte, wurde daher aufgehoben. Dies scheint eine geringfügige Sprach-Kuriosität zu sein, aber die Verwendung von Generatoren und try...finally ist tatsächlich notwendig, um die with-Anweisung zu implementieren, die in PEP 343 beschrieben wird. Ich werde diese neue Anweisung im folgenden Abschnitt behandeln.
Eine weitere, noch esoterischere Auswirkung dieser Änderung: Zuvor war das gi_frame-Attribut eines Generators immer ein Frame-Objekt. Es ist nun möglich, dass gi_frame None ist, sobald der Generator erschöpft ist.
Siehe auch
- PEP 342 - Coroutinen über erweiterte Generatoren
PEP verfasst von Guido van Rossum und Phillip J. Eby; implementiert von Phillip J. Eby. Enthält Beispiele für einige anspruchsvollere Verwendungen von Generatoren als Coroutinen.
Frühere Versionen dieser Features wurden in PEP 288 von Raymond Hettinger und PEP 325 von Samuele Pedroni vorgeschlagen.
- https://en.wikipedia.org/wiki/Coroutine
Der Wikipedia-Eintrag für Coroutinen.
- https://web.archive.org/web/20160321211320/http://www.sidhe.org/~dan/blog/archives/000178.html
Eine Erklärung von Coroutinen aus Perl-Sicht, verfasst von Dan Sugalski.
PEP 343: Die ‚with‘-Anweisung¶
Die ‚with‘-Anweisung vereinfacht Code, der zuvor try...finally-Blöcke verwendete, um sicherzustellen, dass Aufräumcode ausgeführt wird. In diesem Abschnitt bespreche ich die Anweisung, wie sie üblicherweise verwendet wird. Im nächsten Abschnitt untersuche ich die Implementierungsdetails und zeige, wie Objekte für die Verwendung mit dieser Anweisung geschrieben werden.
Die ‚with‘-Anweisung ist eine neue Kontrollflussstruktur, deren grundlegende Struktur lautet:
with expression [as variable]:
with-block
Der Ausdruck wird ausgewertet und sollte ein Objekt ergeben, das das Kontextmanagement-Protokoll unterstützt (d. h. __enter__() und __exit__()-Methoden hat.
Die __enter__()-Methode des Objekts wird aufgerufen, bevor der *with-Block* ausgeführt wird, und kann daher Setup-Code ausführen. Sie kann auch einen Wert zurückgeben, der an den Namen *variable* gebunden wird, falls dieser angegeben ist. (Beachten Sie sorgfältig, dass *variable* *nicht* das Ergebnis von *expression* zugewiesen bekommt.)
Nach Abschluss der Ausführung des *with-Blocks* wird die __exit__()-Methode des Objekts aufgerufen, auch wenn der Block eine Ausnahme ausgelöst hat, und kann daher Aufräumcode ausführen.
Um die Anweisung in Python 2.5 zu aktivieren, müssen Sie die folgende Direktive zu Ihrem Modul hinzufügen:
from __future__ import with_statement
Die Anweisung wird in Python 2.6 immer aktiviert sein.
Einige Standard-Python-Objekte unterstützen nun das Kontextmanagement-Protokoll und können mit der ‚with‘-Anweisung verwendet werden. Dateiobjekte sind ein Beispiel:
with open('/etc/passwd', 'r') as f:
for line in f:
print line
... more processing code ...
Nachdem diese Anweisung ausgeführt wurde, wird das Dateiobjekt in *f* automatisch geschlossen worden sein, selbst wenn die for-Schleife mitten im Block eine Ausnahme ausgelöst hat.
Hinweis
In diesem Fall ist *f* dasselbe Objekt, das von open() erstellt wurde, da __enter__() *self* zurückgibt.
Die Sperren und Bedingungsvariablen des threading-Moduls unterstützen ebenfalls die ‚with‘-Anweisung:
lock = threading.Lock()
with lock:
# Critical section of code
...
Die Sperre wird erworben, bevor der Block ausgeführt wird, und immer freigegeben, sobald der Block abgeschlossen ist.
Die neue Funktion localcontext() im decimal-Modul erleichtert das Speichern und Wiederherstellen des aktuellen Dezimalkontextes, der die gewünschte Präzision und Rundungscharakteristik für Berechnungen verkörpert.
from decimal import Decimal, Context, localcontext
# Displays with default precision of 28 digits
v = Decimal('578')
print v.sqrt()
with localcontext(Context(prec=16)):
# All code in this block uses a precision of 16 digits.
# The original context is restored on exiting the block.
print v.sqrt()
Kontextmanager schreiben¶
Unter der Haube ist die ‚with‘-Anweisung recht kompliziert. Die meisten Leute werden ‚with‘ nur in Verbindung mit vorhandenen Objekten verwenden und müssen diese Details nicht kennen, daher können Sie den Rest dieses Abschnitts überspringen, wenn Sie möchten. Autoren neuer Objekte müssen die Details der zugrunde liegenden Implementierung verstehen und sollten weiterlesen.
Eine High-Level-Erklärung des Kontextmanagement-Protokolls lautet:
Der Ausdruck wird ausgewertet und sollte ein Objekt namens „Kontextmanager“ ergeben. Der Kontextmanager muss
__enter__()und__exit__()-Methoden haben.Die
__enter__()-Methode des Kontextmanagers wird aufgerufen. Der zurückgegebene Wert wird VAR zugewiesen. Wenn keine Klausel *'as VAR'* vorhanden ist, wird der Wert einfach verworfen.Der Code in *BLOCK* wird ausgeführt.
Wenn *BLOCK* eine Ausnahme auslöst, wird
__exit__(type, value, traceback)mit den Ausnahmedetails aufgerufen, denselben Werten, die vonsys.exc_info()zurückgegeben werden. Der Rückgabewert der Methode steuert, ob die Ausnahme erneut ausgelöst wird: Jeder falsche Wert löst die Ausnahme erneut aus, undTrueführt dazu, dass sie unterdrückt wird. Sie werden die Ausnahme nur selten unterdrücken wollen, denn wenn Sie dies tun, wird der Autor des Codes, der die ‚with‘-Anweisung enthält, nie bemerken, dass etwas schiefgelaufen ist.Wenn *BLOCK* keine Ausnahme auslöst, wird die
__exit__()-Methode immer noch aufgerufen, aber *type*, *value* und *traceback* sind alleNone.
Betrachten wir ein Beispiel. Ich werde keinen detaillierten Code präsentieren, sondern nur die notwendigen Methoden für eine Datenbank, die Transaktionen unterstützt, skizzieren.
(Für Personen, die mit Datenbankterminologie nicht vertraut sind: Eine Reihe von Änderungen an der Datenbank wird zu einer Transaktion zusammengefasst. Transaktionen können entweder committed (festgeschrieben) werden, was bedeutet, dass alle Änderungen in die Datenbank geschrieben werden, oder rolled back (zurückgerollt), was bedeutet, dass alle Änderungen verworfen werden und die Datenbank unverändert bleibt. Weitere Informationen finden Sie in jedem Datenbanklehrbuch.)
Nehmen wir an, es gibt ein Objekt, das eine Datenbankverbindung repräsentiert. Unser Ziel wird es sein, den Benutzer Code schreiben zu lassen wie diesen:
db_connection = DatabaseConnection()
with db_connection as cursor:
cursor.execute('insert into ...')
cursor.execute('delete from ...')
# ... more operations ...
Die Transaktion sollte committed werden, wenn der Code im Block fehlerfrei ausgeführt wird, oder rolled back, wenn eine Ausnahme auftritt. Hier ist die grundlegende Schnittstelle für DatabaseConnection, die ich annehmen werde:
class DatabaseConnection:
# Database interface
def cursor (self):
"Returns a cursor object and starts a new transaction"
def commit (self):
"Commits current transaction"
def rollback (self):
"Rolls back current transaction"
Die __enter__()-Methode ist ziemlich einfach und muss nur eine neue Transaktion starten. Für diese Anwendung wäre das resultierende Cursor-Objekt ein nützliches Ergebnis, daher gibt die Methode es zurück. Der Benutzer kann dann as cursor zu seiner ‚with‘-Anweisung hinzufügen, um den Cursor an einen Variablennamen zu binden.
class DatabaseConnection:
...
def __enter__ (self):
# Code to start a new transaction
cursor = self.cursor()
return cursor
Die __exit__()-Methode ist am kompliziertesten, da dort die meiste Arbeit geleistet werden muss. Die Methode muss prüfen, ob eine Ausnahme aufgetreten ist. Wenn keine Ausnahme vorlag, wird die Transaktion committed. Die Transaktion wird zurückgerollt, wenn eine Ausnahme aufgetreten ist.
Im folgenden Code wird die Ausführung einfach am Ende der Funktion enden und den Standardwert von None zurückgeben. None ist falsch, daher wird die Ausnahme automatisch erneut ausgelöst. Wenn Sie möchten, könnten Sie expliziter sein und eine return-Anweisung an der markierten Stelle hinzufügen.
class DatabaseConnection:
...
def __exit__ (self, type, value, tb):
if tb is None:
# No exception, so commit
self.commit()
else:
# Exception occurred, so rollback.
self.rollback()
# return False
Das Modul `contextlib`¶
Das neue Modul contextlib bietet einige Funktionen und einen Dekorator, die nützlich für das Schreiben von Objekten für die Verwendung mit der ‚with‘-Anweisung sind.
Der Dekorator heißt contextmanager() und ermöglicht Ihnen, eine einzelne Generatorfunktion zu schreiben, anstatt eine neue Klasse zu definieren. Der Generator sollte genau einen Wert liefern. Der Code bis zum yield wird als __enter__()-Methode ausgeführt, und der gelieferte Wert wird der Rückgabewert der Methode sein, der an die Variable in der ‚with‘-Anweisungs as-Klausel gebunden wird, falls vorhanden. Der Code nach dem yield wird in der __exit__()-Methode ausgeführt. Jede im Block ausgelöste Ausnahme wird von der yield-Anweisung ausgelöst.
Unser Datenbankbeispiel aus dem vorherigen Abschnitt könnte mit diesem Dekorator wie folgt geschrieben werden:
from contextlib import contextmanager
@contextmanager
def db_transaction (connection):
cursor = connection.cursor()
try:
yield cursor
except:
connection.rollback()
raise
else:
connection.commit()
db = DatabaseConnection()
with db_transaction(db) as cursor:
...
Das Modul contextlib hat auch eine Funktion nested(mgr1, mgr2, ...), die eine Anzahl von Kontextmanagern kombiniert, sodass Sie keine verschachtelten ‚with‘-Anweisungen schreiben müssen. In diesem Beispiel starten die einzelne ‚with‘-Anweisung sowohl eine Datenbanktransaktion als auch erwirbt eine Thread-Sperre:
lock = threading.Lock()
with nested (db_transaction(db), lock) as (cursor, locked):
...
Schließlich gibt die Funktion closing(object) das Objekt zurück, damit es an eine Variable gebunden werden kann, und ruft object.close am Ende des Blocks auf.
import urllib, sys
from contextlib import closing
with closing(urllib.urlopen('http://www.yahoo.com')) as f:
for line in f:
sys.stdout.write(line)
Siehe auch
- PEP 343 - Die „with“-Anweisung
PEP verfasst von Guido van Rossum und Nick Coghlan; implementiert von Mike Bland, Guido van Rossum und Neal Norwitz. Die PEP zeigt den für eine ‚
with‘-Anweisung generierten Code, was beim Erlernen der Funktionsweise der Anweisung hilfreich sein kann.
Die Dokumentation für das Modul contextlib.
PEP 352: Ausnahmen als neue Klassen¶
Ausnahmeklassen können nun neue Klassen sein, nicht nur klassische Klassen, und die eingebaute Klasse Exception und alle standardmäßigen eingebauten Ausnahmen (NameError, ValueError usw.) sind jetzt neue Klassen.
Die Vererbungshierarchie für Ausnahmen wurde leicht umgestaltet. In 2.5 sind die Vererbungsbeziehungen:
BaseException # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
|- (all other current built-in exceptions)
Diese Umgestaltung wurde vorgenommen, weil Leute oft alle Ausnahmen abfangen möchten, die Programmfehler anzeigen. KeyboardInterrupt und SystemExit sind jedoch keine Fehler und stellen normalerweise eine explizite Aktion dar, wie z. B. das Drücken von Control-C durch den Benutzer oder Code, der sys.exit() aufruft. Ein leeres except: fängt alle Ausnahmen ab, daher müssen Sie normalerweise KeyboardInterrupt und SystemExit auflisten, um sie erneut auszulösen. Das übliche Muster ist:
try:
...
except (KeyboardInterrupt, SystemExit):
raise
except:
# Log error...
# Continue running program...
In Python 2.5 können Sie nun except Exception schreiben, um dasselbe Ergebnis zu erzielen, wobei alle Ausnahmen abgefangen werden, die normalerweise Fehler anzeigen, aber KeyboardInterrupt und SystemExit unberührt bleiben. Wie in früheren Versionen fängt ein leeres except: immer noch alle Ausnahmen ab.
Das Ziel für Python 3.0 ist es, zu verlangen, dass jede Klasse, die als Ausnahme ausgelöst wird, von BaseException oder einem Nachfolger von BaseException abgeleitet wird, und zukünftige Versionen der Python 2.x-Reihe können beginnen, diese Einschränkung durchzusetzen. Daher schlage ich vor, dass Sie nun alle Ihre Ausnahmeklassen von Exception ableiten. Es wurde vorgeschlagen, dass die leere except:-Form in Python 3.0 entfernt werden sollte, aber Guido van Rossum hat noch nicht entschieden, ob er dies tun wird oder nicht.
Das Auslösen von Zeichenketten als Ausnahmen, wie in der Anweisung raise "Error occurred", ist in Python 2.5 veraltet und löst eine Warnung aus. Ziel ist es, die Funktion für Zeichenketten-Ausnahmen in einigen Versionen entfernen zu können.
Siehe auch
- PEP 352 - Erforderliche Oberklasse für Ausnahmen
PEP verfasst von Brett Cannon und Guido van Rossum; implementiert von Brett Cannon.
PEP 353: Verwendung von ssize_t als Index-Typ¶
Eine weitreichende Änderung an Pythons C-API, die eine neue Py_ssize_t-Typdefinition anstelle von int verwendet, wird es dem Interpreter ermöglichen, mehr Daten auf 64-Bit-Plattformen zu verarbeiten. Diese Änderung beeinträchtigt nicht Pythons Kapazität auf 32-Bit-Plattformen.
Verschiedene Teile des Python-Interpreters verwendeten den C-Typ int, um Größen oder Anzahlen zu speichern; zum Beispiel wurden die Anzahl der Elemente in einer Liste oder einem Tupel in einem int gespeichert. Die C-Compiler für die meisten 64-Bit-Plattformen definieren int immer noch als 32-Bit-Typ, sodass Listen nur bis zu 2**31 - 1 = 2147483647 Elemente enthalten konnten. (Es gibt tatsächlich einige verschiedene Programmiermodelle, die 64-Bit-C-Compiler verwenden können – siehe https://unix.org/version2/whatsnew/lp64_wp.html für eine Diskussion – aber das am häufigsten verfügbare Modell belässt int als 32 Bit.)
Eine Grenze von 2147483647 Elementen spielt auf einer 32-Bit-Plattform keine wirkliche Rolle, da man den Speicherplatz aufbrauchen würde, bevor man die Längenbegrenzung erreicht. Jedes Listenelement benötigt Speicherplatz für einen Zeiger, der 4 Bytes groß ist, plus Speicherplatz für ein PyObject, das das Element repräsentiert. 2147483647*4 sind bereits mehr Bytes, als ein 32-Bit-Adressraum aufnehmen kann.
Auf einer 64-Bit-Plattform ist es jedoch möglich, so viel Speicher anzusprechen. Die Zeiger für eine Liste dieser Größe würden nur 16 GiB Speicherplatz benötigen, sodass es nicht unwahrscheinlich ist, dass Python-Programmierer so große Listen erstellen. Daher musste der Python-Interpreter geändert werden, um einen anderen Typ als int zu verwenden, und dies wird ein 64-Bit-Typ auf 64-Bit-Plattformen sein. Die Änderung verursacht Inkompatibilitäten auf 64-Bit-Maschinen, daher wurde es als lohnenswert erachtet, den Übergang jetzt zu machen, während die Anzahl der 64-Bit-Benutzer noch relativ gering ist. (In 5 oder 10 Jahren sind wir vielleicht *alle* auf 64-Bit-Maschinen, und der Übergang wäre dann schmerzhafter.)
Diese Änderung betrifft am stärksten Autoren von C-Erweiterungsmodulen. Python-Zeichenketten und Container-Typen wie Listen und Tupel verwenden nun Py_ssize_t, um ihre Größe zu speichern. Funktionen wie PyList_Size() geben nun Py_ssize_t zurück. Code in Erweiterungsmodulen muss daher möglicherweise einige Variablen in Py_ssize_t ändern.
Die Funktionen PyArg_ParseTuple() und Py_BuildValue() haben einen neuen Konvertierungscode, n, für Py_ssize_t. s# und t# von PyArg_ParseTuple() geben standardmäßig immer noch int aus, aber Sie können das Makro PY_SSIZE_T_CLEAN definieren, bevor Sie Python.h einschließen, damit sie Py_ssize_t zurückgeben.
PEP 353 enthält einen Abschnitt über Konvertierungsrichtlinien, den Erweiterungsautoren lesen sollten, um mehr über die Unterstützung von 64-Bit-Plattformen zu erfahren.
Siehe auch
- PEP 353 - Verwendung von ssize_t als Index-Typ
PEP verfasst und implementiert von Martin von Löwis.
PEP 357: Die Methode ‚__index__‘¶
Die NumPy-Entwickler hatten ein Problem, das nur durch die Hinzufügung einer neuen speziellen Methode, __index__(), gelöst werden konnte. Bei der Verwendung von Slice-Notation, wie in [start:stop:step], müssen die Werte der Indizes *start*, *stop* und *step* entweder ganze Zahlen oder lange ganze Zahlen sein. NumPy definiert eine Vielzahl von spezialisierten Ganzzahltypen, die vorzeichenlosen und vorzeichenbehafteten Ganzzahlen von 8, 16, 32 und 64 Bit entsprechen, aber es gab keine Möglichkeit, zu signalisieren, dass diese Typen als Slice-Indizes verwendet werden können.
Slicing kann nicht einfach die vorhandene __int__()-Methode verwenden, da diese Methode auch zur Implementierung der Umwandlung in Ganzzahlen verwendet wird. Wenn Slicing __int__() verwenden würde, würden auch Gleitkommazahlen zu legalen Slice-Indizes werden, und das ist eindeutig ein unerwünschtes Verhalten.
Stattdessen wurde eine neue spezielle Methode namens __index__() hinzugefügt. Sie nimmt keine Argumente und gibt eine Ganzzahl zurück, die den zu verwendenden Slice-Index darstellt. Zum Beispiel:
class C:
def __index__ (self):
return self.value
Der Rückgabewert muss entweder eine Python-Ganzzahl oder eine lange Ganzzahl sein. Der Interpreter prüft, ob der zurückgegebene Typ korrekt ist, und löst einen TypeError aus, wenn diese Anforderung nicht erfüllt ist.
Ein entsprechender nb_index-Slot wurde zur PyNumberMethods-Struktur auf C-Ebene hinzugefügt, damit C-Erweiterungen dieses Protokoll implementieren können. PyNumber_Index(obj) kann in Erweiterungscode verwendet werden, um die __index__()-Funktion aufzurufen und ihr Ergebnis abzurufen.
Siehe auch
- PEP 357 - Zulassen, dass jedes Objekt für Slicing verwendet wird
PEP verfasst und implementiert von Travis Oliphant.
Andere Sprachänderungen¶
Hier sind alle Änderungen, die Python 2.5 an der Kernsprache Python vornimmt.
Der Typ
dicthat einen neuen Hook, der es Unterklassen ermöglicht, einen Standardwert bereitzustellen, wenn ein Schlüssel nicht im Wörterbuch enthalten ist. Wenn ein Schlüssel nicht gefunden wird, wird die__missing__(key)-Methode des Wörterbuchs aufgerufen. Dieser Hook wird verwendet, um die neue Klassedefaultdictim Modulcollectionszu implementieren. Das folgende Beispiel definiert ein Wörterbuch, das Null für jeden fehlenden Schlüssel zurückgibt:class zerodict (dict): def __missing__ (self, key): return 0 d = zerodict({1:1, 2:2}) print d[1], d[2] # Prints 1, 2 print d[3], d[4] # Prints 0, 0
Sowohl 8-Bit- als auch Unicode-Zeichenketten haben neue
partition(sep)- undrpartition(sep)-Methoden, die einen häufigen Anwendungsfall vereinfachen.Die Methode
find(S)wird oft verwendet, um einen Index zu erhalten, der dann zum Slicen der Zeichenkette verwendet wird, um die Teile vor und nach dem Trennzeichen zu erhalten.partition(sep)fasst dieses Muster in einem einzigen Methodenaufruf zusammen, der ein 3-Tupel zurückgibt, das die Teilzeichenkette vor dem Trennzeichen, das Trennzeichen selbst und die Teilzeichenkette nach dem Trennzeichen enthält. Wenn das Trennzeichen nicht gefunden wird, ist das erste Element des Tupels die gesamte Zeichenkette und die beiden anderen Elemente sind leer.rpartition(sep)gibt ebenfalls ein 3-Tupel zurück, beginnt aber die Suche vom Ende der Zeichenkette an; dasrsteht für ‚reverse‘ (umgekehrt).Einige Beispiele
>>> ('https://pythonlang.de').partition('://') ('http', '://', 'www.python.org') >>> ('file:/usr/share/doc/index.html').partition('://') ('file:/usr/share/doc/index.html', '', '') >>> (u'Subject: a quick question').partition(':') (u'Subject', u':', u' a quick question') >>> 'www.python.org'.rpartition('.') ('www.python', '.', 'org') >>> 'www.python.org'.rpartition(':') ('', '', 'www.python.org')
(Implementiert von Fredrik Lundh nach einem Vorschlag von Raymond Hettinger.)
Die Methoden
startswith()undendswith()von Zeichenkettentypen akzeptieren nun Tupel von Zeichenketten zum Prüfen.def is_image_file (filename): return filename.endswith(('.gif', '.jpg', '.tiff'))
(Implementiert von Georg Brandl nach einem Vorschlag von Tom Lynn.)
Die eingebauten Funktionen
min()undmax()erhielten einen Schlüsselwortparameterkey, analog zum Argumentkeyfürsort(). Dieser Parameter liefert eine Funktion, die ein einzelnes Argument entgegennimmt und für jeden Wert in der Liste aufgerufen wird;min()/max()gibt das Element mit dem kleinsten/größten Rückgabewert dieser Funktion zurück. Um beispielsweise die längste Zeichenkette in einer Liste zu finden, können Sie tun:L = ['medium', 'longest', 'short'] # Prints 'longest' print max(L, key=len) # Prints 'short', because lexicographically 'short' has the largest value print max(L)
(Beigetragen von Steven Bethard und Raymond Hettinger.)
Zwei neue eingebaute Funktionen,
any()undall(), werten aus, ob ein Iterator wahre oder falsche Werte enthält.any()gibtTruezurück, wenn ein vom Iterator zurückgegebener Wert wahr ist; andernfalls gibt erFalsezurück.all()gibt nur dannTruezurück, wenn alle vom Iterator zurückgegebenen Werte als wahr ausgewertet werden. (Vorgeschlagen von Guido van Rossum und implementiert von Raymond Hettinger.)Das Ergebnis der Methode
__hash__()einer Klasse kann nun entweder eine lange Ganzzahl oder eine reguläre Ganzzahl sein. Wenn eine lange Ganzzahl zurückgegeben wird, wird der Hash-Wert dieser Zahl ermittelt. In früheren Versionen musste der Hash-Wert eine reguläre Ganzzahl sein, aber in 2.5 wurde die eingebaute Funktionid()so geändert, dass sie immer nicht-negative Zahlen zurückgibt, und Benutzer verwenden häufigid(self)in__hash__()-Methoden (obwohl dies nicht empfohlen wird).ASCII ist nun die Standardkodierung für Module. Es ist nun ein Syntaxfehler, wenn ein Modul String-Literale mit 8-Bit-Zeichen enthält, aber keine Kodierungsdeklaration hat. In Python 2.4 löste dies eine Warnung, keinen Syntaxfehler, aus. Siehe PEP 263, um die Kodierung eines Moduls zu deklarieren; Sie können beispielsweise eine Zeile wie diese am Anfang der Quelldatei hinzufügen
# -*- coding: latin1 -*-Eine neue Warnung,
UnicodeWarning, wird ausgelöst, wenn Sie versuchen, einen Unicode-String mit einem 8-Bit-String zu vergleichen, der nicht mit der Standard-ASCII-Kodierung in Unicode konvertiert werden kann. Das Ergebnis des Vergleichs ist falsch>>> chr(128) == unichr(128) # Can't convert chr(128) to Unicode __main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal False >>> chr(127) == unichr(127) # chr(127) can be converted True
Zuvor hätte dies eine
UnicodeDecodeError-Ausnahme ausgelöst, aber in 2.5 konnte dies zu verwirrenden Problemen beim Zugriff auf ein Wörterbuch führen. Wenn Sieunichr(128)nachgeschlagen hätten undchr(128)als Schlüssel verwendet worden wäre, hätten Sie eineUnicodeDecodeError-Ausnahme erhalten. Andere Änderungen in 2.5 führten dazu, dass diese Ausnahme anstelle der Unterdrückung durch den Code indictobject.c, der Wörterbücher implementiert, ausgelöst wurde.Das Auslösen einer Ausnahme für einen solchen Vergleich ist streng genommen korrekt, aber die Änderung hätte Code brechen können. Stattdessen wurde
UnicodeWarningeingeführt.(Implementiert von Marc-André Lemburg.)
Ein Fehler, den Python-Programmierer manchmal machen, ist das Vergessen, ein
__init__.py-Modul in einem Paketverzeichnis einzufügen. Das Debuggen dieses Fehlers kann verwirrend sein und erfordert normalerweise das Ausführen von Python mit der Option-v, um alle durchsuchten Pfade zu protokollieren. In Python 2.5 wird eine neueImportWarning-Warnung ausgelöst, wenn ein Import ein Verzeichnis als Paket erkennen würde, aber kein__init__.pygefunden wurde. Diese Warnung wird standardmäßig stillschweigend ignoriert. Geben Sie die Option-Wdan, wenn Sie die Python-Executable ausführen, um die Warnmeldung anzuzeigen. (Implementiert von Thomas Wouters.)Die Liste der Basisklassen in einer Klassendefinition kann nun leer sein. Zum Beispiel ist dies nun legal
class C(): pass
(Implementiert von Brett Cannon.)
Änderungen am interaktiven Interpreter¶
Im interaktiven Interpreter waren quit und exit lange Zeit Strings, sodass neue Benutzer eine einigermaßen hilfreiche Nachricht erhielten, wenn sie versuchten, das Programm zu beenden
>>> quit
'Use Ctrl-D (i.e. EOF) to exit.'
In Python 2.5 sind quit und exit nun Objekte, die immer noch ihre String-Darstellungen von sich selbst produzieren, aber auch aufrufbar sind. Anfänger, die quit() oder exit() versuchen, werden nun den Interpreter wie erwartet beenden. (Implementiert von Georg Brandl.)
Die Python-Executable akzeptiert nun die Standard-Langoptionen --help und --version; unter Windows akzeptiert sie auch die Option /? zur Anzeige einer Hilfemeldung. (Implementiert von Georg Brandl.)
Optimierungen¶
Mehrere der Optimierungen wurden auf dem NeedForSpeed-Sprint entwickelt, einer Veranstaltung, die vom 21. bis 28. Mai 2006 in Reykjavik, Island, stattfand. Der Sprint konzentrierte sich auf Geschwindigkeitsverbesserungen der CPython-Implementierung und wurde von EWT LLC mit lokaler Unterstützung von CCP Games finanziert. Die auf diesem Sprint vorgenommenen Optimierungen sind in der folgenden Liste speziell gekennzeichnet.
Als sie in Python 2.4 eingeführt wurden, basierten die eingebauten Typen
setundfrozensetauf dem Dictionary-Typ von Python. In 2.5 wurde die interne Datenstruktur für die Implementierung von Sets angepasst, und als Ergebnis werden Sets ein Drittel weniger Speicher verbrauchen und etwas schneller sein. (Implementiert von Raymond Hettinger.)Die Geschwindigkeit einiger Unicode-Operationen, wie z. B. das Finden von Teilstrings, das Aufteilen von Strings sowie die Kodierung und Dekodierung von Zeichenkarten, wurde verbessert. (Verbesserungen bei der Suche nach Teilstrings und beim Aufteilen wurden von Fredrik Lundh und Andrew Dalke auf dem NeedForSpeed-Sprint hinzugefügt. Zeichenkarten wurden von Walter Dörwald und Martin von Löwis verbessert.)
Die Funktion
long(str, base)ist bei langen Zeichenketten nun schneller, da weniger Zwischenergebnisse berechnet werden. Der Spitzenwert wird für Zeichenketten mit etwa 800–1000 Ziffern erreicht, wo die Funktion 6-mal schneller ist. (Beigesteuert von Alan McIntyre und auf dem NeedForSpeed-Sprint commitet.)Es ist nun illegal, die Iteration über eine Datei mit
for line in filemit dem Aufruf der Methodenread()/readline()/readlines()des Datei-Objekts zu mischen. Die Iteration verwendet einen internen Puffer, und dieread*()-Methoden verwenden diesen Puffer nicht. Stattdessen würden sie die Daten nach dem Puffer zurückgeben, was dazu führt, dass die Daten außer Reihenfolge erscheinen. Das Mischen von Iteration und diesen Methoden löst nun einenValueErrorvon derread*()-Methode aus. (Implementiert von Thomas Wouters.)Das Modul
structkompiliert nun Strukturformatzeichenfolgen in eine interne Darstellung und speichert diese Darstellung zwischen, was zu einer Geschwindigkeitssteigerung von 20% führt. (Beigesteuert von Bob Ippolito auf dem NeedForSpeed-Sprint.)Das Modul
rehat eine Geschwindigkeitssteigerung von 1 oder 2 % erzielt, indem es auf die Allokationsfunktionen von Python anstelle der Systemfunktionenmalloc()undfree()umgestellt wurde. (Beigesteuert von Jack Diederich auf dem NeedForSpeed-Sprint.)Der Peephole-Optimierer des Codegenerators führt nun einfache Konstantenfaltung in Ausdrücken durch. Wenn Sie etwas wie
a = 2+3schreiben, führt der Codegenerator die Arithmetik durch und erzeugt Code, dera = 5entspricht. (Vorgeschlagen und implementiert von Raymond Hettinger.)Funktionsaufrufe sind nun schneller, da Code-Objekte den zuletzt abgeschlossenen Frame (einen "Zombie-Frame") in einem internen Feld des Code-Objekts behalten und ihn beim nächsten Aufruf des Code-Objekts wiederverwenden. (Original-Patch von Michael Hudson, modifiziert von Armin Rigo und Richard Jones; auf dem NeedForSpeed-Sprint committet.) Frame-Objekte sind auch etwas kleiner, was die Cache-Lokalität verbessern und den Speicherverbrauch etwas reduzieren kann. (Beigesteuert von Neal Norwitz.)
Die eingebauten Ausnahmen von Python sind nun New-Style-Klassen, eine Änderung, die die Instanziierung erheblich beschleunigt. Die Ausnahmebehandlung in Python 2.5 ist daher etwa 30 % schneller als in 2.4. (Beigesteuert von Richard Jones, Georg Brandl und Sean Reifschneider auf dem NeedForSpeed-Sprint.)
Das Importieren speichert nun die versuchten Pfade zwischen und zeichnet auf, ob sie existieren oder nicht, sodass der Interpreter beim Start weniger
open()- undstat()-Aufrufe macht. (Beigesteuert von Martin von Löwis und Georg Brandl.)
Neue, verbesserte und entfernte Module¶
Die Standardbibliothek erhielt in Python 2.5 viele Verbesserungen und Fehlerbehebungen. Hier ist eine Teilliste der bemerkenswertesten Änderungen, alphabetisch nach Modulnamen sortiert. Konsultieren Sie die Datei Misc/NEWS im Quellcode-Baum für eine vollständigere Liste der Änderungen oder werfen Sie einen Blick in die SVN-Protokolle für alle Details.
Das Modul
audioopunterstützt nun die a-LAW-Kodierung, und der Code für die u-LAW-Kodierung wurde verbessert. (Beigesteuert von Lars Immisch.)Das Modul
codecserhielt Unterstützung für inkrementelle Codecs. Die Funktioncodec.lookup()gibt nun eineCodecInfo-Instanz anstelle eines Tupels zurück.CodecInfo-Instanzen verhalten sich wie ein 4-Tupel, um die Abwärtskompatibilität zu wahren, haben aber auch die Attributeencode,decode,incrementalencoder,incrementaldecoder,streamwriterundstreamreader. Inkrementelle Codecs können Eingaben empfangen und Ausgaben in mehreren Blöcken produzieren; die Ausgabe ist dieselbe, als ob die gesamte Eingabe an den nicht-inkrementellen Codec übergeben worden wäre. Details finden Sie in der Dokumentation des Modulscodecs. (Entworfen und implementiert von Walter Dörwald.)Das Modul
collectionserhielt einen neuen Typ,defaultdict, der vom Standardtypdictabgeleitet ist. Der neue Typ verhält sich meist wie ein Dictionary, erstellt aber einen Standardwert, wenn ein Schlüssel nicht vorhanden ist, und fügt ihn automatisch für den angeforderten Schlüsselwert zum Dictionary hinzu.Das erste Argument für den Konstruktor von
defaultdictist eine Factory-Funktion, die aufgerufen wird, wenn ein Schlüssel angefordert, aber nicht gefunden wird. Diese Factory-Funktion erhält keine Argumente, sodass Sie eingebaute Typkonstruktoren wielist()oderint()verwenden können. Sie können beispielsweise einen Index von Wörtern basierend auf ihrem Anfangsbuchstaben erstellen, indem Sie wie folgt vorgehenwords = """Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura che la diritta via era smarrita""".lower().split() index = defaultdict(list) for w in words: init_letter = w[0] index[init_letter].append(w)
Das Drucken von
indexergibt die folgende Ausgabedefaultdict(<type 'list'>, {'c': ['cammin', 'che'], 'e': ['era'], 'd': ['del', 'di', 'diritta'], 'm': ['mezzo', 'mi'], 'l': ['la'], 'o': ['oscura'], 'n': ['nel', 'nostra'], 'p': ['per'], 's': ['selva', 'smarrita'], 'r': ['ritrovai'], 'u': ['una'], 'v': ['vita', 'via']}
(Beigesteuert von Guido van Rossum.)
Der von dem Modul
collectionsbereitgestellte Typ der doppelseitigen Warteschlangedequeverfügt nun über eine Methoderemove(value), die das erste Vorkommen von value in der Warteschlange entfernt und eineValueErrorauslöst, wenn der Wert nicht gefunden wird. (Beigesteuert von Raymond Hettinger.)Neues Modul: Das Modul
contextlibenthält Hilfsfunktionen für die Verwendung mit der neuen ' 'with'-Anweisung. Weitere Informationen zu diesem Modul finden Sie in Abschnitt Das Modul contextlib.Neues Modul: Das Modul
cProfileist eine C-Implementierung des bestehenden Modulsprofile, die einen deutlich geringeren Overhead aufweist. Die Schnittstelle des Moduls ist dieselbe wie die vonprofile: Sie rufencProfile.run('main()')auf, um eine Funktion zu profilieren, können Profildaten in eine Datei speichern usw. Es ist noch nicht bekannt, ob der Hotshot-Profiler, der ebenfalls in C geschrieben ist, aber nicht mit der Schnittstelle des Modulsprofileübereinstimmt, in zukünftigen Versionen von Python weiter gepflegt wird. (Beigesteuert von Armin Rigo.)Außerdem unterstützt das Modul
pstatszur Analyse der vom Profiler gemessenen Daten die Ausgabe an jedes beliebige Datei-Objekt, indem ein stream-Argument an den Konstruktor vonStatsübergeben wird. (Beigesteuert von Skip Montanaro.)Das Modul
csv, das Dateien im durch Trennzeichen getrennten Wertformat analysiert, erhielt mehrere Verbesserungen und eine Reihe von Fehlerbehebungen. Sie können nun die maximale Größe eines Feldes in Bytes festlegen, indem Sie die Funktioncsv.field_size_limit(new_limit)aufrufen; wenn new_limit weggelassen wird, wird das aktuell eingestellte Limit zurückgegeben. Die Klassereaderverfügt nun über ein Attributline_num, das die Anzahl der physischen Zeilen zählt, die aus der Quelle gelesen wurden. Datensätze können sich über mehrere physische Zeilen erstrecken, daher istline_numnicht dasselbe wie die Anzahl der gelesenen Datensätze.Der CSV-Parser ist nun strenger bezüglich mehrzeiliger Anführungsfelder. Zuvor, wenn eine Zeile innerhalb eines Anführungsfeldes ohne abschließendes Zeilenumbruchzeichen endete, wurde ein Zeilenumbruch in das zurückgegebene Feld eingefügt. Dieses Verhalten verursachte Probleme beim Lesen von Dateien, die Wagenrücklaufzeichen innerhalb von Feldern enthielten, daher wurde der Code geändert, um das Feld ohne Einfügen von Zeilenumbrüchen zurückzugeben. Infolgedessen, wenn Zeilenumbrüche innerhalb von Feldern wichtig sind, sollte die Eingabe so in Zeilen aufgeteilt werden, dass die Zeilenumbruchzeichen erhalten bleiben.
(Beigesteuert von Skip Montanaro und Andrew McNamara.)
Die Klasse
datetimeim Moduldatetimeverfügt nun über eine Methodestrptime(string, format)zum Parsen von Datumsstrings, beigesteuert von Josh Spoerri. Sie verwendet dieselben Formatzeichen wietime.strptime()undtime.strftime()from datetime import datetime ts = datetime.strptime('10:13:15 2006-03-07', '%H:%M:%S %Y-%m-%d')
Die Methode
SequenceMatcher.get_matching_blocks()im Moduldifflibgarantiert nun die Rückgabe einer minimalen Liste von Blöcken, die übereinstimmende Teilsequenzen beschreiben. Zuvor teilte der Algorithmus gelegentlich einen Block übereinstimmender Elemente in zwei Listeneinträge auf. (Verbesserung von Tim Peters.)Das Modul
doctesthat eine OptionSKIPerhalten, die verhindert, dass ein Beispiel überhaupt ausgeführt wird. Dies ist für Code-Snippets gedacht, die Nutzungsbeispiele für den Leser sind und keine tatsächlichen Testfälle.Ein Parameter encoding wurde zur Funktion
testfile()und zur KlasseDocFileSuitehinzugefügt, um die Kodierung der Datei anzugeben. Dies erleichtert die Verwendung von Nicht-ASCII-Zeichen in Tests, die in einem Docstring enthalten sind. (Beigesteuert von Björn Tillenius.)Das Paket
emailwurde auf Version 4.0 aktualisiert. (Beigesteuert von Barry Warsaw.)Das Modul
fileinputwurde flexibler gestaltet. Unicode-Dateinamen werden nun unterstützt, und ein Parameter mode, der standardmäßig auf"r"gesetzt ist, wurde zur Funktioninput()hinzugefügt, um das Öffnen von Dateien im Binär- oder Universal-Newlines-Modus zu ermöglichen. Ein weiterer neuer Parameter, openhook, ermöglicht die Verwendung einer anderen Funktion alsopen()zum Öffnen der Eingabedateien. Sobald Sie über die Menge der Dateien iterieren, gibt die neue Methodefileno()des ObjektsFileInputden Dateideskriptor für die aktuell geöffnete Datei zurück. (Beigesteuert von Georg Brandl.)Im Modul
gcgibt die neue Funktionget_count()ein 3-Tupel zurück, das die aktuellen Zählungen für die drei GC-Generationen enthält. Dies sind Buchhaltungsdaten für den Garbage Collector; wenn diese Zählungen einen bestimmten Schwellenwert erreichen, wird eine Garbage-Collection durchgeführt. Die bestehende Funktiongc.collect()nimmt nun ein optionales Argument generation von 0, 1 oder 2 an, um anzugeben, welche Generation gesammelt werden soll. (Beigesteuert von Barry Warsaw.)Die Funktionen
nsmallest()undnlargest()im Modulheapqunterstützen nun einen Schlüsselwortparameterkey, ähnlich dem, der von den Funktionenmin()/max()und den Methodensort()bereitgestellt wird. Zum Beispiel>>> import heapq >>> L = ["short", 'medium', 'longest', 'longer still'] >>> heapq.nsmallest(2, L) # Return two lowest elements, lexicographically ['longer still', 'longest'] >>> heapq.nsmallest(2, L, key=len) # Return two shortest elements ['short', 'medium']
(Beigetragen von Raymond Hettinger.)
Die Funktion
itertools.islice()akzeptiert nunNonefür die Argumente start und step. Dies macht sie kompatibler mit den Attributen von Slice-Objekten, sodass Sie nun Folgendes schreiben könnens = slice(5) # Create slice object itertools.islice(iterable, s.start, s.stop, s.step)
(Beigetragen von Raymond Hettinger.)
Die Funktion
format()im Modullocalewurde geändert und zwei neue Funktionen wurden hinzugefügt:format_string()undcurrency().Der Parameter val der Funktion
format()konnte bisher ein String sein, solange nicht mehr als ein %char-Spezifizierer vorkam; jetzt muss der Parameter genau ein %char-Spezifizierer ohne umgebenden Text sein. Ein optionaler Parameter monetary wurde ebenfalls hinzugefügt, der, wenn er aufTruegesetzt ist, die Regeln des Locales zur Formatierung von Währung verwendet, um einen Trenner zwischen Dreiergruppen von Ziffern zu setzen.Um Strings mit mehreren %char-Spezifizierern zu formatieren, verwenden Sie die neue Funktion
format_string(), die wieformat()funktioniert, aber auch die Mischung von %char-Spezifizierern mit beliebigem Text unterstützt.Eine neue Funktion
currency()wurde ebenfalls hinzugefügt, die eine Zahl gemäß den Einstellungen des aktuellen Locales formatiert.(Beigesteuert von Georg Brandl.)
Das Modul
mailboxwurde massiv überarbeitet, um die Fähigkeit hinzuzufügen, Mailboxen zu modifizieren und nicht nur zu lesen. Eine neue Reihe von Klassen, daruntermbox,MHundMaildir, wird verwendet, um Mailboxen zu lesen, und verfügt über eine Methodeadd(message)zum Hinzufügen von Nachrichten,remove(key)zum Entfernen von Nachrichten undlock()/unlock()zum Sperren/Entsperren der Mailbox. Das folgende Beispiel konvertiert eine Mailbox im Maildir-Format in eine im mbox-Formatimport mailbox # 'factory=None' uses email.Message.Message as the class representing # individual messages. src = mailbox.Maildir('maildir', factory=None) dest = mailbox.mbox('/tmp/mbox') for msg in src: dest.add(msg)
(Beigesteuert von Gregory K. Johnson. Die Finanzierung erfolgte durch Googles Summer of Code 2005.)
Neues Modul: Das Modul
msilibermöglicht die Erstellung von Microsoft Installer.msi-Dateien und CAB-Dateien. Einige Unterstützung für das Lesen der.msi-Datenbank ist ebenfalls enthalten. (Beigesteuert von Martin von Löwis.)Das Modul
nisunterstützt nun den Zugriff auf andere Domänen als die Systemstandarddomäne, indem ein Argument domain an die Funktionennis.match()undnis.maps()übergeben wird. (Beigesteuert von Ben Bell.)Die Funktionen
itemgetter()undattrgetter()des Modulsoperatorunterstützen nun mehrere Felder. Ein Aufruf wieoperator.attrgetter('a', 'b')gibt eine Funktion zurück, die die Attributeaundbabruft. Die Kombination dieses neuen Features mit dem Parameterkeyder Methodesort()ermöglicht es Ihnen, Listen einfach anhand mehrerer Felder zu sortieren. (Beigesteuert von Raymond Hettinger.)Das Modul
optparsewurde auf Version 1.5.1 der Optik-Bibliothek aktualisiert. Die KlasseOptionParserhat ein Attributepilogerhalten, eine Zeichenkette, die nach der Hilfemeldung ausgegeben wird, und eine Methodedestroy(), um Referenzzyklen zu brechen, die vom Objekt erzeugt wurden. (Beigesteuert von Greg Ward.)Das Modul
oshat mehrere Änderungen erfahren. Die Variablestat_float_timesist nun standardmäßig auf true gesetzt, was bedeutet, dassos.stat()nun Zeitwerte als Fließkommazahlen zurückgibt. (Das bedeutet nicht zwangsläufig, dassos.stat()Zeiten mit Bruchteilen von Sekunden zurückgibt; nicht alle Systeme unterstützen eine solche Präzision.)Konstanten mit den Namen
os.SEEK_SET,os.SEEK_CURundos.SEEK_ENDwurden hinzugefügt; dies sind die Parameter für die Funktionos.lseek(). Zwei neue Konstanten für das Sperren sindos.O_SHLOCKundos.O_EXLOCK.Zwei neue Funktionen,
wait3()undwait4(), wurden hinzugefügt. Sie ähneln der Funktionwaitpid(), die auf das Beenden eines Kindprozesses wartet und ein Tupel aus der Prozess-ID und seinem Exit-Status zurückgibt.wait3()undwait4()geben jedoch zusätzliche Informationen zurück.wait3()nimmt keine Prozess-ID als Eingabe entgegen, wartet also auf den Exit eines beliebigen Kindprozesses und gibt ein 3-Tupel aus Prozess-ID, Exit-Status, Ressourcen-Nutzung zurück, wie es von der Funktionresource.getrusage()zurückgegeben wird.wait4(pid)nimmt eine Prozess-ID entgegen. (Beigesteuert von Chad J. Schroeder.)Unter FreeBSD gibt die Funktion
os.stat()nun Zeiten mit Nanosekundenauflösung zurück, und das zurückgegebene Objekt hat nunst_genundst_birthtime. Das Attributst_flagsist ebenfalls verfügbar, wenn die Plattform dies unterstützt. (Beigesteuert von Antti Louko und Diego Pettenò.)Der von dem Modul
pdbbereitgestellte Python-Debugger kann nun Listen von Befehlen speichern, die ausgeführt werden sollen, wenn ein Haltepunkt erreicht und die Ausführung gestoppt wird. Sobald Haltepunkt #1 erstellt wurde, geben Siecommands 1ein und geben eine Reihe von auszuführenden Befehlen ein, wobei Sie die Liste mitendabschließen. Die Befehlsliste kann Befehle enthalten, die die Ausführung fortsetzen, wie z. B.continueodernext. (Beigesteuert von Grégoire Dooms.)Die Module
pickleundcPickleakzeptieren keinen Rückgabewert vonNonemehr von der Methode__reduce__(); die Methode muss stattdessen ein Tupel von Argumenten zurückgeben. Die Möglichkeit,Nonezurückzugeben, wurde in Python 2.4 als veraltet markiert, daher ist dies die vollständige Entfernung der Funktion.Das Modul
pkgutil, das verschiedene Hilfsfunktionen zum Auffinden von Paketen enthält, wurde um die Unterstützung für die Import-Hooks von PEP 302 erweitert und funktioniert nun auch für in ZIP-Archiven gespeicherte Pakete. (Beigetragen von Phillip J. Eby.)Die Benchmark-Suite pybench von Marc-André Lemburg ist jetzt im Verzeichnis
Tools/pybenchenthalten. Die pybench-Suite ist eine Verbesserung des weit verbreiteten Programmspystone.py, da pybench eine detailliertere Messung der Interpretergeschwindigkeit liefert. Es misst bestimmte Operationen wie Funktionsaufrufe, Tupelschneiden, Methodensuche und numerische Operationen, anstatt viele verschiedene Operationen durchzuführen und das Ergebnis auf eine einzige Zahl zu reduzieren, wie espystone.pytut.Das Modul
pyexpatverwendet nun Version 2.0 des Expat-Parsers. (Beigetragen von Trent Mick.)Die Klasse
Queuedes ModulsQueueerhielt zwei neue Methoden.join()blockiert, bis alle Elemente in der Queue abgerufen und alle Verarbeitungsarbeiten an den Elementen abgeschlossen sind. Worker-Threads rufen die andere neue Methode,task_done(), auf, um zu signalisieren, dass die Verarbeitung eines Elements abgeschlossen ist. (Beigetragen von Raymond Hettinger.)Die alten Module
regexundregsub, die seit Python 2.0 veraltet waren, wurden endlich gelöscht. Weitere gelöschte Module:statcache,tzparse,whrandom.Ebenfalls gelöscht: Das Verzeichnis
lib-old, das veraltete Module wiedircmpundnienthält, wurde entfernt.lib-oldbefand sich nicht im Standard-sys.path, sodass diese Entfernung Ihre Programme nicht beeinträchtigen sollte, es sei denn, Sie haben das Verzeichnis explizit zusys.pathhinzugefügt.Das Modul
rlcompleterist nicht mehr auf den Import des Modulsreadlineangewiesen und funktioniert daher nun auch auf Nicht-Unix-Plattformen. (Patch von Robert Kiendl.)Die Klassen
SimpleXMLRPCServerundDocXMLRPCServerhaben jetzt ein Attributrpc_paths, das XML-RPC-Operationen auf eine begrenzte Menge von URL-Pfaden beschränkt; standardmäßig sind nur'/'und'/RPC2'erlaubt. Das Setzen vonrpc_pathsaufNoneoder ein leeres Tupel deaktiviert diese Pfadprüfung.Das Modul
socketunterstützt nunAF_NETLINKSockets unter Linux, dank eines Patches von Philippe Biondi. Netlink-Sockets sind ein Linux-spezifischer Mechanismus zur Kommunikation zwischen einem User-Space-Prozess und Kernel-Code; ein einführender Artikel dazu ist unter https://www.linuxjournal.com/article/7356 zu finden. In Python-Code werden Netlink-Adressen als Tupel aus 2 Integern dargestellt,(pid, group_mask).Zwei neue Methoden für Socket-Objekte,
recv_into(buffer)undrecvfrom_into(buffer), speichern die empfangenen Daten in einem Objekt, das das Buffer-Protokoll unterstützt, anstatt die Daten als String zurückzugeben. Das bedeutet, dass Sie die Daten direkt in ein Array oder eine speicherabgebildete Datei legen können.Socket-Objekte haben außerdem die Getter-Methoden
getfamily(),gettype()undgetproto()erhalten, um die Familien-, Typ- und Protokollwerte für den Socket abzurufen.Neues Modul: Das Modul
spwdstellt Funktionen zum Zugriff auf die Shadow-Passwortdatenbank auf Systemen bereit, die Shadow-Passwörter unterstützen.Das Modul
structist jetzt schneller, da es Format-Strings inStruct-Objekte mit den Methodenpack()undunpack()kompiliert. Dies ähnelt der Art und Weise, wie das Modulredas Erstellen kompilierter regulärer Ausdrucksobjekte ermöglicht. Sie können weiterhin die Modul-Level-Funktionenpack()undunpack()verwenden; diese erstellenStruct-Objekte und cachen sie. Oder Sie könnenStruct-Instanzen direkt verwenden.s = struct.Struct('ih3s') data = s.pack(1972, 187, 'abc') year, number, name = s.unpack(data)
Sie können Daten auch direkt in und aus Buffer-Objekten packen und entpacken, indem Sie die Methoden
pack_into(buffer, offset, v1, v2, ...)undunpack_from(buffer, offset)verwenden. Dies ermöglicht es Ihnen, Daten direkt in ein Array oder eine speicherabgebildete Datei zu speichern.(
Struct-Objekte wurden von Bob Ippolito auf dem NeedForSpeed-Sprint implementiert. Die Unterstützung für Buffer-Objekte wurde von Martin Blais ebenfalls auf dem NeedForSpeed-Sprint hinzugefügt.)Die Python-Entwickler wechselten während des Entwicklungsprozesses von 2.5 von CVS zu Subversion. Informationen über die genaue Build-Version sind als Variable
sys.subversionverfügbar, ein 3-Tupel aus(interpreter-name, branch-name, revision-range). Zum Zeitpunkt des Schreibens meldete meine Kopie von 2.5 zum Beispiel('CPython', 'trunk', '45313:45315').Diese Informationen sind auch für C-Erweiterungen über die Funktion
Py_GetBuildInfo()verfügbar, die einen String mit Build-Informationen zurückgibt, wie z. B.:"trunk:45355:45356M, Apr 13 2006, 07:42:19". (Beigetragen von Barry Warsaw.)Eine weitere neue Funktion,
sys._current_frames(), gibt die aktuellen Stack-Frames aller laufenden Threads als Dictionary zurück, das Thread-Identifikatoren auf den obersten Stack-Frame abbildet, der zu dem Zeitpunkt, an dem die Funktion aufgerufen wird, in diesem Thread am aktivsten ist. (Beigetragen von Tim Peters.)Die Klasse
TarFileim Modultarfilehat nun eine Methodeextractall(), die alle Mitglieder aus dem Archiv in das aktuelle Arbeitsverzeichnis extrahiert. Es ist auch möglich, ein anderes Verzeichnis als Extraktionsziel festzulegen und nur einen Teil der Mitglieder des Archivs zu entpacken.Die Komprimierung, die für eine im Stream-Modus geöffnete Tarfile verwendet wird, kann jetzt mit dem Modus
'r|*'automatisch erkannt werden. (Beigetragen von Lars Gustäbel.)Das Modul
threadingerlaubt es Ihnen nun, die Stack-Größe festzulegen, die beim Erstellen neuer Threads verwendet wird. Die Funktionstack_size([*size*])gibt die aktuell konfigurierte Stack-Größe zurück, und die Angabe des optionalen Parameters size setzt einen neuen Wert. Nicht alle Plattformen unterstützen die Änderung der Stack-Größe, aber Windows, POSIX-Threading und OS/2 tun dies alle. (Beigetragen von Andrew MacIntyre.)Das Modul
unicodedatawurde aktualisiert, um Version 4.1.0 der Unicode-Datenbank zu verwenden. Version 3.2.0 wird von einigen Spezifikationen benötigt, daher ist sie weiterhin alsunicodedata.ucd_3_2_0verfügbar.Neues Modul: Das Modul
uuidgeneriert universell eindeutige Bezeichner (UUIDs) gemäß RFC 4122. Die RFC definiert mehrere verschiedene UUID-Versionen, die aus einer Startzeichenkette, aus System-Eigenschaften oder rein zufällig generiert werden. Dieses Modul enthält eine KlasseUUIDund Funktionen namensuuid1(),uuid3(),uuid4()unduuid5(), um verschiedene UUID-Versionen zu generieren. (Version 2 UUIDs sind in RFC 4122 nicht spezifiziert und werden von diesem Modul nicht unterstützt.)>>> import uuid >>> # make a UUID based on the host ID and current time >>> uuid.uuid1() UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') >>> # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') >>> # make a random UUID >>> uuid.uuid4() UUID('16fd2706-8baf-433b-82eb-8c7fada847da') >>> # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
(Beigetragen von Ka-Ping Yee.)
Die Typen
WeakKeyDictionaryundWeakValueDictionarydes Modulsweakreferhielten neue Methoden zur Iteration über die in der Datenstruktur enthaltenen schwachen Referenzen. Die Methodeniterkeyrefs()undkeyrefs()wurden zuWeakKeyDictionaryhinzugefügt, unditervaluerefs()undvaluerefs()wurden zuWeakValueDictionaryhinzugefügt. (Beigetragen von Fred L. Drake, Jr.)Das Modul
webbrowsererhielt eine Reihe von Verbesserungen. Es kann nun als Skript mitpython -m webbrowserverwendet werden, wobei eine URL als Argument übergeben wird; es gibt eine Reihe von Schaltern, um das Verhalten zu steuern (-nfür ein neues Browserfenster,-tfür einen neuen Tab). Neue Modul-Level-Funktionen,open_new()undopen_new_tab(), wurden hinzugefügt, um dies zu unterstützen. Die Funktionopen()des Moduls unterstützt eine zusätzliche Funktion, einen autoraise-Parameter, der angibt, ob das geöffnete Fenster, wenn möglich, aktiviert werden soll. Eine Reihe von zusätzlichen Browsern wurden zur unterstützten Liste hinzugefügt, wie z. B. Firefox, Opera, Konqueror und elinks. (Beigetragen von Oleg Broytmann und Georg Brandl.)Das Modul
xmlrpclibunterstützt nun die Rückgabe vondatetime-Objekten für den XML-RPC-Datums-Typ. Übergeben Sieuse_datetime=Truean die Funktionloads()oder die KlasseUnmarshaller, um diese Funktion zu aktivieren. (Beigetragen von Skip Montanaro.)Das Modul
zipfileunterstützt nun die ZIP64-Version des Formats, was bedeutet, dass ein .zip-Archiv nun größer als 4 GiB sein und einzelne Dateien von mehr als 4 GiB enthalten kann. (Beigetragen von Ronald Oussoren.)Die Objekte
CompressundDecompressdes Modulszlibunterstützen nun eine Methodecopy(), die den internen Zustand des Objekts kopiert und ein neuesCompress- oderDecompress-Objekt zurückgibt. (Beigetragen von Chris AtLee.)
Das ctypes-Paket¶
Das Paket ctypes, geschrieben von Thomas Heller, wurde der Standardbibliothek hinzugefügt. ctypes ermöglicht es Ihnen, beliebige Funktionen in Shared Libraries oder DLLs aufzurufen. Langjährige Benutzer erinnern sich vielleicht an das Modul dl, das Funktionen zum Laden von Shared Libraries und zum Aufrufen von Funktionen darin bereitstellt. Das Paket ctypes ist viel umfangreicher.
Um eine Shared Library oder DLL zu laden, müssen Sie eine Instanz der Klasse CDLL erstellen und den Namen oder Pfad der Shared Library oder DLL angeben. Sobald dies geschehen ist, können Sie beliebige Funktionen aufrufen, indem Sie sie als Attribute des CDLL-Objekts abrufen.
import ctypes
libc = ctypes.CDLL('libc.so.6')
result = libc.printf("Line of output\n")
Typkonstruktoren für die verschiedenen C-Typen werden bereitgestellt: c_int(), c_float(), c_double(), c_char_p() (entspricht char*) und so weiter. Im Gegensatz zu Pythons Typen sind die C-Versionen alle veränderbar; Sie können ihr Attribut value zuweisen, um den umschlossenen Wert zu ändern. Python-Integer und -Strings werden automatisch in die entsprechenden C-Typen konvertiert, aber für andere Typen müssen Sie den richtigen Typkonstruktor aufrufen. (Und ich meine *müssen*; wenn Sie es falsch machen, stürzt der Interpreter oft mit einem Segmentierungsfehler ab.)
Sie sollten c_char_p() nicht mit einem Python-String verwenden, wenn die C-Funktion den Speicherbereich ändern wird, da Python-Strings unveränderlich sein sollen; die Verletzung dieser Regel führt zu rätselhaften Fehlern. Wenn Sie einen veränderbaren Speicherbereich benötigen, verwenden Sie create_string_buffer()
s = "this is a string"
buf = ctypes.create_string_buffer(s)
libc.strfry(buf)
C-Funktionen geben standardmäßig Integer zurück, aber Sie können das Attribut restype des Funktionsobjekts ändern, um dies zu ändern
>>> libc.atof('2.71828')
-1783957616
>>> libc.atof.restype = ctypes.c_double
>>> libc.atof('2.71828')
2.71828
ctypes bietet auch einen Wrapper für Pythons C-API als Objekt ctypes.pythonapi. Dieses Objekt gibt die globale Interpreter-Sperre *nicht* frei, bevor es eine Funktion aufruft, da die Sperre gehalten werden muss, wenn in den Code des Interpreters aufgerufen wird. Es gibt einen Typkonstruktor py_object, der einen PyObject*-Zeiger erstellt. Eine einfache Verwendung
import ctypes
d = {}
ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d),
ctypes.py_object("abc"), ctypes.py_object(1))
# d is now {'abc', 1}.
Vergessen Sie nicht, py_object() zu verwenden; wenn Sie es weglassen, erhalten Sie einen Segmentierungsfehler.
ctypes gibt es schon eine Weile, aber Leute schreiben und verteilen immer noch handgeschriebene Erweiterungsmodule, da man sich nicht darauf verlassen kann, dass ctypes vorhanden ist. Vielleicht werden Entwickler nun Python-Wrapper über Bibliotheken schreiben, die über ctypes angesprochen werden, anstatt Erweiterungsmodule, da ctypes jetzt in der Python-Kernbibliothek enthalten ist.
Siehe auch
- https://web.archive.org/web/20180410025338/http://starship.python.net/crew/theller/ctypes/
Die Pre-Stdlib-ctypes-Webseite mit einem Tutorial, einer Referenz und einer FAQ.
Die Dokumentation für das Modul ctypes.
Das ElementTree-Paket¶
Eine Teilmenge von Fredrik Lundhs ElementTree-Bibliothek zur Verarbeitung von XML wurde als xml.etree in die Standardbibliothek aufgenommen. Die verfügbaren Module sind ElementTree, ElementPath und ElementInclude aus ElementTree 1.2.6. Das Beschleunigungsmodul cElementTree ist ebenfalls enthalten.
Der Rest dieses Abschnitts gibt eine kurze Übersicht über die Verwendung von ElementTree. Die vollständige Dokumentation für ElementTree ist verfügbar unter https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm.
ElementTree repräsentiert ein XML-Dokument als Baum von Knotenelementen. Der Textinhalt des Dokuments wird in den Attributen text und tail des (Dies ist einer der Hauptunterschiede zwischen ElementTree und dem Document Object Model; im DOM gibt es viele verschiedene Knotentypen, einschließlich TextNode.)
Die am häufigsten verwendete Parsing-Funktion ist parse(), die entweder einen String (angenommen, er enthält einen Dateinamen) oder ein dateiähnliches Objekt nimmt und eine ElementTree-Instanz zurückgibt.
from xml.etree import ElementTree as ET
tree = ET.parse('ex-1.xml')
feed = urllib.urlopen(
'http://planet.python.org/rss10.xml')
tree = ET.parse(feed)
Sobald Sie eine ElementTree-Instanz haben, können Sie deren Methode getroot() aufrufen, um den Wurzel-Element-Knoten zu erhalten.
Es gibt auch eine Funktion XML(), die einen Zeichenketten-Literal nimmt und einen Element-Knoten zurückgibt (nicht eine ElementTree). Diese Funktion bietet eine saubere Möglichkeit, XML-Fragmente einzubinden, und nähert sich der Bequemlichkeit eines XML-Literals.
svg = ET.XML("""<svg width="10px" version="1.0">
</svg>""")
svg.set('height', '320px')
svg.append(elem1)
Jedes XML-Element unterstützt einige dictionary-ähnliche und einige list-ähnliche Zugriffsmethoden. Dictionary-ähnliche Operationen werden verwendet, um auf Attributwerte zuzugreifen, und list-ähnliche Operationen werden verwendet, um auf Kindknoten zuzugreifen.
Operation |
Ergebnis |
|---|---|
|
Gibt das n-te Kindelement zurück. |
|
Gibt eine Liste der Kindelemente vom m-ten bis zum n-ten zurück. |
|
Gibt die Anzahl der Kindelemente zurück. |
|
Gibt eine Liste von Kindelementen zurück. |
|
Fügt elem2 als Kind hinzu. |
|
Fügt elem2 an der angegebenen Stelle ein. |
|
Löscht das n-te Kindelement. |
|
Gibt eine Liste der Attributnamen zurück. |
|
Gibt den Wert des Attributs name zurück. |
|
Setzt einen neuen Wert für das Attribut name. |
|
Ruft das Dictionary ab, das Attribute enthält. |
|
Löscht das Attribut name. |
Kommentare und Verarbeitungsanweisungen werden ebenfalls als Element-Knoten dargestellt. Um zu prüfen, ob ein Knoten ein Kommentar oder eine Verarbeitungsanweisung ist
if elem.tag is ET.Comment:
...
elif elem.tag is ET.ProcessingInstruction:
...
Um XML-Ausgabe zu generieren, sollten Sie die Methode ElementTree.write() aufrufen. Wie parse() kann sie entweder einen String oder ein dateiähnliches Objekt annehmen.
# Encoding is US-ASCII
tree.write('output.xml')
# Encoding is UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')
(Vorsicht: Die Standardkodierung für die Ausgabe ist ASCII. Für allgemeine XML-Arbeiten, bei denen der Name eines Elements beliebige Unicode-Zeichen enthalten kann, ist ASCII keine sehr nützliche Kodierung, da sie eine Ausnahme auslöst, wenn der Name eines Elements Zeichen mit Werten größer als 127 enthält. Daher ist es am besten, eine andere Kodierung wie UTF-8 anzugeben, die jedes Unicode-Zeichen verarbeiten kann.)
Dieser Abschnitt ist nur eine Teilbeschreibung der ElementTree-Schnittstellen. Bitte lesen Sie die offizielle Dokumentation des Pakets für weitere Details.
Siehe auch
- https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm
Offizielle Dokumentation für ElementTree.
Das hashlib-Paket¶
Ein neues Modul hashlib, geschrieben von Gregory P. Smith, wurde hinzugefügt, um die Module md5 und sha zu ersetzen. hashlib fügt Unterstützung für zusätzliche sichere Hashes hinzu (SHA-224, SHA-256, SHA-384 und SHA-512). Wenn verfügbar, verwendet das Modul OpenSSL für schnelle plattformoptimierte Implementierungen von Algorithmen.
Die alten Module md5 und sha existieren weiterhin als Wrapper um hashlib, um die Abwärtskompatibilität zu gewährleisten. Die Schnittstelle des neuen Moduls ist der der alten Module sehr ähnlich, aber nicht identisch. Der wichtigste Unterschied besteht darin, dass die Konstruktorfunktionen zum Erstellen neuer Hash-Objekte anders benannt sind.
# Old versions
h = md5.md5()
h = md5.new()
# New version
h = hashlib.md5()
# Old versions
h = sha.sha()
h = sha.new()
# New version
h = hashlib.sha1()
# Hash that weren't previously available
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()
# Alternative form
h = hashlib.new('md5') # Provide algorithm as a string
Sobald ein Hash-Objekt erstellt wurde, sind seine Methoden wie zuvor: update(string) hash-t den angegebenen String in den aktuellen Digest-Zustand, digest() und hexdigest() geben den Digest-Wert als Binärstring bzw. als String von Hex-Ziffern zurück, und copy() gibt ein neues Hash-Objekt mit demselben Digest-Zustand zurück.
Siehe auch
Die Dokumentation für das Modul hashlib.
Das sqlite3-Paket¶
Das pysqlite-Modul (https://www.pysqlite.org), ein Wrapper für die eingebettete SQLite-Datenbank, wurde unter dem Paketnamen sqlite3 in die Standardbibliothek aufgenommen.
SQLite ist eine C-Bibliothek, die eine leichtgewichtige, festplattenbasierte Datenbank bereitstellt, die keinen separaten Serverprozess benötigt und den Zugriff auf die Datenbank mit einer nicht standardmäßigen Variante der SQL-Abfragesprache ermöglicht. Einige Anwendungen können SQLite für die interne Datenspeicherung verwenden. Es ist auch möglich, eine Anwendung mit SQLite zu prototypisieren und dann den Code auf eine größere Datenbank wie PostgreSQL oder Oracle zu portieren.
pysqlite wurde von Gerhard Häring geschrieben und bietet eine SQL-Schnittstelle, die der DB-API 2.0-Spezifikation entspricht, wie sie in PEP 249 beschrieben ist.
Wenn Sie den Python-Quellcode selbst kompilieren, beachten Sie, dass der Quellbaum den SQLite-Code nicht enthält, nur das Wrapper-Modul. Sie müssen die SQLite-Bibliotheken und Header installiert haben, bevor Sie Python kompilieren, und der Build-Prozess kompiliert das Modul, wenn die notwendigen Header verfügbar sind.
Um das Modul zu verwenden, müssen Sie zuerst ein Connection-Objekt erstellen, das die Datenbank repräsentiert. Hier werden die Daten in der Datei /tmp/example gespeichert.
conn = sqlite3.connect('/tmp/example')
Sie können auch den speziellen Namen :memory: angeben, um eine Datenbank im RAM zu erstellen.
Sobald Sie eine Connection haben, können Sie ein Cursor-Objekt erstellen und dessen Methode execute() aufrufen, um SQL-Befehle auszuführen.
c = conn.cursor()
# Create table
c.execute('''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')
# Insert a row of data
c.execute("""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")
Normalerweise müssen Ihre SQL-Operationen Werte aus Python-Variablen verwenden. Sie sollten Ihre Abfrage nicht mit Python-Stringoperationen zusammensetzen, da dies unsicher ist und Ihr Programm anfällig für SQL-Injection-Angriffe macht.
Verwenden Sie stattdessen die Parameterersetzung der DB-API. Setzen Sie ? als Platzhalter, wo immer Sie einen Wert verwenden möchten, und geben Sie dann ein Tupel von Werten als zweites Argument für die Methode execute() des Cursors an. (Andere Datenbankmodule können einen anderen Platzhalter verwenden, z. B. %s oder :1.) Zum Beispiel
# Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)
# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)
# Larger example
for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00),
('2006-04-06', 'SELL', 'IBM', 500, 53.00),
):
c.execute('insert into stocks values (?,?,?,?,?)', t)
Um Daten nach der Ausführung einer SELECT-Anweisung abzurufen, können Sie den Cursor entweder als Iterator behandeln, die Methode fetchone() des Cursors aufrufen, um eine einzelne passende Zeile abzurufen, oder fetchall() aufrufen, um eine Liste der passenden Zeilen zu erhalten.
Dieses Beispiel verwendet die Iteratorform.
>>> c = conn.cursor()
>>> c.execute('select * from stocks order by price')
>>> for row in c:
... print row
...
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0)
>>>
Weitere Informationen über die von SQLite unterstützte SQL-Dialekt finden Sie unter https://www.sqlite.org.
Siehe auch
- https://www.pysqlite.org
Die pysqlite-Webseite.
- https://www.sqlite.org
Die SQLite-Webseite; die Dokumentation beschreibt die Syntax und die verfügbaren Datentypen für den unterstützten SQL-Dialekt.
Die Dokumentation für das Modul sqlite3.
- PEP 249 - Database API Specification 2.0
PEP geschrieben von Marc-André Lemburg.
Das Paket wsgiref¶
Die Web Server Gateway Interface (WSGI) v1.0 definiert eine Standard-Schnittstelle zwischen Webservern und Python-Webanwendungen und ist in PEP 333 beschrieben. Das Paket wsgiref ist eine Referenzimplementierung der WSGI-Spezifikation.
Das Paket enthält einen einfachen HTTP-Server, der eine WSGI-Anwendung ausführt; dieser Server ist nützlich zum Debuggen, aber nicht für den Produktionseinsatz gedacht. Das Einrichten eines Servers erfordert nur wenige Codezeilen
from wsgiref import simple_server
wsgi_app = ...
host = ''
port = 8000
httpd = simple_server.make_server(host, port, wsgi_app)
httpd.serve_forever()
Siehe auch
- https://web.archive.org/web/20160331090247/http://wsgi.readthedocs.org/en/latest/
Eine zentrale Website für WSGI-bezogene Ressourcen.
- PEP 333 - Python Web Server Gateway Interface v1.0
PEP geschrieben von Phillip J. Eby.
Build- und C-API-Änderungen¶
Änderungen am Build-Prozess von Python und an der C-API umfassen
Der Python-Quellcodebaum wurde von CVS nach Subversion konvertiert, eine komplexe Migrationsprozedur, die von Martin von Löwis beaufsichtigt und fehlerfrei durchgeführt wurde. Die Prozedur wurde als PEP 347 entwickelt.
Coverity, ein Unternehmen, das ein Quellcode-Analysewerkzeug namens Prevent vermarktet, stellte die Ergebnisse ihrer Untersuchung des Python-Quellcodes zur Verfügung. Die Analyse ergab etwa 60 Fehler, die schnell behoben wurden. Viele der Fehler waren Probleme mit der Referenzzählung, die oft im Fehlerbehandlungscode auftraten. Weitere Statistiken finden Sie unter https://scan.coverity.com.
Die größte Änderung an der C-API kam von PEP 353, die den Interpreter so modifiziert, dass eine
Py_ssize_t-Typdefinition anstelle von int verwendet wird. Eine Erörterung dieser Änderung finden Sie im vorherigen Abschnitt PEP 353: Verwendung von ssize_t als Index-Typ.Das Design des Bytecode-Compilers hat sich stark verändert; er generiert Bytecode nicht mehr durch Durchlaufen des Parse-Trees. Stattdessen wird der Parse-Tree in einen abstrakten Syntaxbaum (oder AST) umgewandelt, und es ist der abstrakte Syntaxbaum, der durchlaufen wird, um den Bytecode zu erzeugen.
Es ist möglich, dass Python-Code AST-Objekte erhält, indem die integrierte Funktion
compile()verwendet und_ast.PyCF_ONLY_ASTals Wert für den Parameter flags angegeben wird.from _ast import PyCF_ONLY_AST ast = compile("""a=0 for i in range(10): a += i """, "<string>", 'exec', PyCF_ONLY_AST) assignment = ast.body[0] for_loop = ast.body[1]
Für den AST-Code wurde noch keine offizielle Dokumentation geschrieben, aber PEP 339 diskutiert das Design. Um mit dem Code vertraut zu werden, lesen Sie die Definition der verschiedenen AST-Knoten in
Parser/Python.asdl. Ein Python-Skript liest diese Datei und generiert eine Reihe von C-Strukturdefinitionen inInclude/Python-ast.h. Die FunktionenPyParser_ASTFromString()undPyParser_ASTFromFile(), die inInclude/pythonrun.hdefiniert sind, nehmen Python-Quellcode als Eingabe und geben die Wurzel eines AST zurück, der den Inhalt repräsentiert. Dieser AST kann dann mitPyAST_Compile()in ein Code-Objekt umgewandelt werden. Weitere Informationen finden Sie im Quellcode und stellen Sie dann Fragen auf python-dev.Der AST-Code wurde unter der Leitung von Jeremy Hylton entwickelt und implementiert von (in alphabetischer Reihenfolge) Brett Cannon, Nick Coghlan, Grant Edwards, John Ehresman, Kurt Kaiser, Neal Norwitz, Tim Peters, Armin Rigo und Neil Schemenauer, sowie von Teilnehmern an einer Reihe von AST-Sprints auf Konferenzen wie PyCon.
Evans Jones' Patch für obmalloc, der erstmals in einem Vortrag auf der PyCon DC 2005 beschrieben wurde, wurde angewendet. Python 2.4 wies kleine Objekte in 256 KB großen Arenen zu, gab die Arenen aber nie frei. Mit diesem Patch gibt Python Arenen frei, wenn sie leer sind. Die Nettoauswirkung ist, dass auf einigen Plattformen, wenn Sie viele Objekte zuweisen, die Speichernutzung von Python tatsächlich sinken kann, wenn Sie sie löschen, und der Speicher an das Betriebssystem zurückgegeben werden kann. (Implementiert von Evan Jones und überarbeitet von Tim Peters.)
Beachten Sie, dass diese Änderung bedeutet, dass Erweiterungsmodule vorsichtiger beim Zuweisen von Speicher sein müssen. Die Python-API bietet viele verschiedene Funktionen zur Speicherzuweisung, die in Familien gruppiert sind. Zum Beispiel sind
PyMem_Malloc(),PyMem_Realloc()undPyMem_Free()eine Familie, die Rohspeicher zuweist, währendPyObject_Malloc(),PyObject_Realloc()undPyObject_Free()eine weitere Familie sind, die für die Erstellung von Python-Objekten verwendet werden soll.Zuvor reduzierten sich diese verschiedenen Familien auf die
malloc()undfree()Funktionen der Plattform. Das bedeutete, dass es keine Rolle spielte, ob Sie Dinge falsch machten und Speicher mit derPyMem-Funktion zuwiesen, ihn aber mit derPyObject-Funktion freigaben. Mit den Änderungen an obmalloc in 2.5 machen diese Familien nun unterschiedliche Dinge und Fehlzuordnungen führen wahrscheinlich zu einem Segfault. Sie sollten Ihre C-Erweiterungsmodule sorgfältig mit Python 2.5 testen.Die integrierten Set-Typen verfügen nun über eine offizielle C-API. Rufen Sie
PySet_New()undPyFrozenSet_New()auf, um ein neues Set zu erstellen,PySet_Add()undPySet_Discard(), um Elemente hinzuzufügen und zu entfernen, sowiePySet_Contains()undPySet_Size(), um den Zustand des Sets zu untersuchen. (Beigesteuert von Raymond Hettinger.)C-Code kann nun Informationen über die genaue Revision des Python-Interpreters abrufen, indem die Funktion
Py_GetBuildInfo()aufgerufen wird, die eine Zeichenkette mit Build-Informationen zurückgibt, wie z. B.:"trunk:45355:45356M, Apr 13 2006, 07:42:19". (Beigesteuert von Barry Warsaw.)Zwei neue Makros können verwendet werden, um C-Funktionen zu kennzeichnen, die lokal für die aktuelle Datei sind, sodass eine schnellere Aufrufkonvention verwendet werden kann.
Py_LOCAL(type)deklariert die Funktion als Rückgabe eines Werts vom angegebenen Typ und verwendet eine schnelle Aufrufqualifizierung.Py_LOCAL_INLINE(type)tut dasselbe und fordert auch an, dass die Funktion inline verwendet wird. Wenn das MakroPY_LOCAL_AGGRESSIVEvor dem Einbinden vonpython.hdefiniert ist, werden für das Modul eine Reihe aggressiverer Optimierungen aktiviert; Sie sollten die Ergebnisse benchmarken, um festzustellen, ob diese Optimierungen den Code tatsächlich schneller machen. (Beigesteuert von Fredrik Lundh beim NeedForSpeed-Sprint.)PyErr_NewException(name, base, dict)kann jetzt ein Tupel von Basisklassen als sein base-Argument akzeptieren. (Beigesteuert von Georg Brandl.)Die Funktion
PyErr_Warn()zum Ausgeben von Warnungen ist nun veraltet zugunsten vonPyErr_WarnEx(category, message, stacklevel), die es Ihnen ermöglicht, die Anzahl der Stack-Frames anzugeben, die diese Funktion vom Aufrufer trennen. Ein stacklevel von 1 ist die Funktion, diePyErr_WarnEx()aufruft, 2 ist die Funktion darüber und so weiter. (Hinzugefügt von Neal Norwitz.)Der CPython-Interpreter ist immer noch in C geschrieben, aber der Code kann nun fehlerfrei mit einem C++-Compiler kompiliert werden. (Implementiert von Anthony Baxter, Martin von Löwis, Skip Montanaro.)
Die Funktion
PyRange_New()wurde entfernt. Sie wurde nie dokumentiert, nie im Kerncode verwendet und hatte eine gefährlich nachgiebige Fehlerprüfung. In dem unwahrscheinlichen Fall, dass Ihre Erweiterungen sie verwendet haben, können Sie sie durch etwas wie das Folgende ersetzenrange = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll", start, stop, step);
Port-spezifische Änderungen¶
MacOS X (10.3 und höher): dynamisches Laden von Modulen verwendet nun die Funktion
dlopen()anstelle von MacOS-spezifischen Funktionen.MacOS X: dem configure-Skript wurde ein Schalter
--enable-universalsdkhinzugefügt, der den Interpreter als Universal-Binärdatei kompiliert, die sowohl auf PowerPC- als auch auf Intel-Prozessoren ausgeführt werden kann. (Beigesteuert von Ronald Oussoren; bpo-2573.)Windows:
.dllwird nicht mehr als Dateinamenerweiterung für Erweiterungsmodule unterstützt..pydist nun die einzige Dateinamenerweiterung, nach der gesucht wird.
Portierung auf Python 2.5¶
Dieser Abschnitt listet die zuvor beschriebenen Änderungen auf, die Änderungen an Ihrem Code erfordern könnten.
ASCII ist nun die Standardkodierung für Module. Es ist nun ein Syntaxfehler, wenn ein Modul Zeichenfolgenliterale mit 8-Bit-Zeichen enthält, aber keine Kodierungsdeklaration hat. In Python 2.4 löste dies eine Warnung aus, keinen Syntaxfehler.
Zuvor war das Attribut
gi_frameeines Generators immer ein Frame-Objekt. Aufgrund der in Abschnitt PEP 342: Neue Generatorfunktionen beschriebenen PEP 342-Änderungen kanngi_framenunNonesein.Eine neue Warnung,
UnicodeWarning, wird ausgelöst, wenn versucht wird, eine Unicode-Zeichenfolge und eine 8-Bit-Zeichenfolge zu vergleichen, die nicht mit der Standard-ASCII-Kodierung in Unicode konvertiert werden kann. Zuvor lösten solche Vergleiche eine AusnahmeUnicodeDecodeErroraus.Bibliothek: Das Modul
csvist nun strenger bezüglich mehrzeiliger Anführungsfelder. Wenn Ihre Dateien Zeilenumbrüche enthalten, die in Feldern eingebettet sind, sollten die Eingaben so in Zeilen aufgeteilt werden, dass die Zeilenumbruchzeichen erhalten bleiben.Bibliothek: Die Funktion
format()des Modulslocaleakzeptierte zuvor jede Zeichenkette, solange nicht mehr als ein %char-Spezifizierer vorkam. In Python 2.5 muss das Argument genau ein %char-Spezifizierer ohne umgebenden Text sein.Bibliothek: Die Module
pickleundcPickleakzeptieren keinen Rückgabewert vonNonemehr von der Methode__reduce__(); die Methode muss stattdessen ein Tupel von Argumenten zurückgeben. Die Module akzeptieren auch nicht mehr den veralteten bin-Schlüsselwortparameter.Bibliothek: Die Klassen
SimpleXMLRPCServerundDocXMLRPCServerhaben nun ein Attributrpc_paths, das XML-RPC-Operationen auf eine begrenzte Anzahl von URL-Pfaden beschränkt; standardmäßig sind nur'/'und'/RPC2'erlaubt. Das Setzen vonrpc_pathsaufNoneoder ein leeres Tupel deaktiviert diese Pfadprüfung.C API: Viele Funktionen verwenden nun
Py_ssize_tanstelle von int, um auf 64-Bit-Maschinen mehr Daten verarbeiten zu können. Der Erweiterungscode muss möglicherweise die gleiche Änderung vornehmen, um Warnungen zu vermeiden und 64-Bit-Maschinen zu unterstützen. Eine Erörterung dieser Änderung finden Sie im vorherigen Abschnitt PEP 353: Verwendung von ssize_t als Index-Typ.C API: Die obmalloc-Änderungen bedeuten, dass Sie vorsichtig sein müssen, die Verwendung der Familien von Funktionen
PyMem_*undPyObject_*nicht zu mischen. Speicher, der mit der*_Malloc-Funktion einer Familie zugewiesen wurde, muss mit der*_Free-Funktion der entsprechenden Familie freigegeben werden.
Danksagungen¶
Der Autor möchte den folgenden Personen für ihre Vorschläge, Korrekturen und Unterstützung bei verschiedenen Entwürfen dieses Artikels danken: Georg Brandl, Nick Coghlan, Phillip J. Eby, Lars Gustäbel, Raymond Hettinger, Ralf W. Grosse-Kunstleve, Kent Johnson, Iain Lowe, Martin von Löwis, Fredrik Lundh, Andrew McNamara, Skip Montanaro, Gustavo Niemeyer, Paul Prescod, James Pryor, Mike Rovner, Scott Weikart, Barry Warsaw, Thomas Wouters.