Wenn Sie in anderen Sprachen codieren, erstellen Sie manchmal einen Blockbereich wie folgt:
statement
...
statement
{
statement
...
statement
}
statement
...
statement
Ein (von vielen) Zweck besteht darin, die Lesbarkeit des Codes zu verbessern: zu zeigen, dass bestimmte Anweisungen eine logische Einheit bilden oder dass bestimmte lokale Variablen nur in diesem Block verwendet werden.
Gibt es eine idiomatische Möglichkeit, dasselbe in Python zu tun?
One purpose (of many) is to improve code readability
- Richtig geschriebener Python-Code (dh nach dem Zen von Python ) würde eine solche Verzierung nicht benötigen, um lesbar zu sein. Tatsächlich ist es eines der (vielen) Dinge, die ich an Python mag.__exit__
undwith
Aussage zu spielen , das zu ändern,globals()
aber ich habe versagt.Antworten:
Nein, es gibt keine Sprachunterstützung zum Erstellen eines Blockbereichs.
Die folgenden Konstrukte erstellen einen Bereich:
quelle
Die idiomatische Methode in Python besteht darin, Ihre Funktionen kurz zu halten. Wenn Sie glauben, dass Sie dies benötigen, überarbeiten Sie Ihren Code! :) :)
Python erstellt einen neuen Bereich für jedes Modul, jede Klasse, Funktion, jeden Generatorausdruck, jedes Diktatverständnis, jedes Mengenverständnis und in Python 3.x auch für jedes Listenverständnis. Abgesehen von diesen gibt es innerhalb von Funktionen keine verschachtelten Bereiche.
quelle
Sie können etwas Ähnliches wie einen C ++ - Blockbereich in Python tun, indem Sie eine Funktion in Ihrer Funktion deklarieren und sie dann sofort aufrufen. Beispielsweise:
Wenn Sie sich nicht sicher sind, warum Sie dies tun möchten, kann Sie dieses Video überzeugen.
Das Grundprinzip besteht darin, alles so eng wie möglich
do_first_thing()
zu erfassen, ohne dass "Müll" (zusätzliche Typen / Funktionen) in einen größeren Bereich als unbedingt erforderlich eingeführt wird. Nichts anderes möchte die Methode beispielsweise verwenden, damit sie nicht außerhalb des Bereichs liegt Funktion aufrufen.quelle
Ich bin damit einverstanden, dass es keinen Blockumfang gibt. Aber eine Stelle in Python 3 lässt es so aussehen, als hätte es einen Blockbereich.
Was ist passiert, was diesen Blick gab? Dies funktionierte in Python 2 ordnungsgemäß, aber um die variable Leckage in Python 3 zu stoppen, haben sie diesen Trick ausgeführt, und diese Änderung lässt es so aussehen, als hätte es hier einen Blockbereich.
Lassen Sie mich erklären.
Wenn wir Variablen mit demselben Namen in denselben Bereich einführen, sollte gemäß der Idee des Bereichs der Wert geändert werden.
Dies ist, was in Python 2 passiert
Obwohl in Python 3 die gleichnamige Variable eingeführt wird, wird sie nicht überschrieben. Das Listenverständnis verhält sich aus irgendeinem Grund wie eine Sandbox und scheint darin einen neuen Bereich zu erstellen.
und diese Antwort widerspricht der Aussage von answerer @ Thomas. Das einzige Mittel zum Erstellen eines Bereichs sind Funktionen, Klassen oder Module, da dies wie ein anderer Ort zum Erstellen eines neuen Bereichs aussieht.
quelle
Module (und Pakete) sind eine großartige pythonische Möglichkeit, Ihr Programm in separate Namespaces zu unterteilen, was ein implizites Ziel dieser Frage zu sein scheint. Als ich die Grundlagen von Python lernte, war ich frustriert über das Fehlen einer Block-Scope-Funktion. Sobald ich jedoch die Python-Module verstanden hatte, konnte ich meine vorherigen Ziele eleganter verwirklichen, ohne dass ein Blockumfang erforderlich war.
Als Motivation und um die Menschen in die richtige Richtung zu weisen, halte ich es für nützlich, explizite Beispiele für einige der Scoping-Konstrukte von Python zu geben. Zuerst erkläre ich meinen fehlgeschlagenen Versuch, Python-Klassen zum Implementieren des Blockbereichs zu verwenden. Als nächstes erkläre ich, wie ich mit Python-Modulen etwas Nützlicheres erreicht habe. Am Ende skizziere ich eine praktische Anwendung von Paketen zum Laden und Filtern von Daten.
Blockbereich mit Klassen versuchen
Für einige Momente dachte ich, ich hätte den Blockumfang erreicht, indem ich Code in eine Klassendeklaration gesteckt habe:
Leider bricht dies zusammen, wenn eine Funktion definiert wird:
Dies liegt daran, dass innerhalb einer Klasse definierte Funktionen einen globalen Bereich verwenden. Der einfachste (wenn auch nicht der einzige) Weg, dies zu beheben, besteht darin, die Klasse explizit anzugeben:
Dies ist nicht so elegant, da man Funktionen unterschiedlich schreiben muss, je nachdem, ob sie in einer Klasse enthalten sind oder nicht.
Bessere Ergebnisse mit Python-Modulen
Module sind statischen Klassen sehr ähnlich, aber Module sind meiner Erfahrung nach viel sauberer. Um dasselbe mit Modulen zu tun, erstelle ich eine
my_module.py
im aktuellen Arbeitsverzeichnis aufgerufene Datei mit folgendem Inhalt:Dann mache ich es in meiner Hauptdatei oder in einer interaktiven Sitzung (z. B. Jupyter)
Zur Erklärung definiert jede Python-Datei ein Modul mit einem eigenen globalen Namespace. Durch das Importieren eines Moduls können Sie mit der
.
Syntax auf die Variablen in diesem Namespace zugreifen .Wenn Sie in einer interaktiven Sitzung mit Modulen arbeiten, können Sie diese beiden Zeilen zu Beginn ausführen
und Module werden automatisch neu geladen, wenn die entsprechenden Dateien geändert werden.
Pakete zum Laden und Filtern von Daten
Die Idee der Pakete ist eine leichte Erweiterung des Modulkonzepts. Ein Paket ist ein Verzeichnis mit einer (möglicherweise leeren)
__init__.py
Datei, die beim Import ausgeführt wird. Auf Module / Pakete in diesem Verzeichnis kann mit der.
Syntax zugegriffen werden .Für die Datenanalyse muss ich häufig eine große Datendatei lesen und dann interaktiv verschiedene Filter anwenden. Das Lesen einer Datei dauert einige Minuten, daher möchte ich es nur einmal tun. Basierend auf dem, was ich in der Schule über objektorientiertes Programmieren gelernt habe, war ich der Meinung, dass man den Code zum Filtern und Laden als Methoden in einer Klasse schreiben sollte. Ein Hauptnachteil dieses Ansatzes besteht darin, dass sich die Definition meiner Klasse ändert, wenn ich meine Filter neu definiere, sodass ich die gesamte Klasse einschließlich der Daten neu laden muss.
Heutzutage definiere ich mit Python ein Paket namens,
my_data
das Submodule mit dem Namenload
und enthältfilter
. Innerhalb vonfilter.py
kann ich einen relativen Import durchführen:Wenn ich ändere
filter.py
,autoreload
werden die Änderungen erkannt. Es wird nicht neu geladenload.py
, daher muss ich meine Daten nicht neu laden. Auf diese Weise kann ich meinen Filtercode in einem Jupyter-Notizbuch prototypisieren, als Funktion umschließen und dann direkt aus meinem Notizbuch ausschneiden und einfügenfilter.py
. Das herauszufinden hat meinen Workflow revolutioniert und mich von einem Skeptiker zu einem Gläubigen des „Zen of Python“ gemacht.quelle