Python: Was bringt es, "Import" zu verwenden?

8

Ich bin in diesem Aspekt nicht sehr klar. Angenommen, Sie haben eine Reihe von .py-Dateien, die ihre eigenen separaten Module sind.

Warum muss jede .py-Datei die anderen importieren, wenn sie diese Klasse verwenden? Oder doch? Weil ich mir ziemlich sicher war, dass andere Sprachen (z. B. Java) keinen Import benötigten, wenn auf Klassen / Dateien im selben Verzeichnis verwiesen wurde. Ich könnte falsch liegen.

Kaitlyn Mcmordie
quelle

Antworten:

8

Einfach gesagt, so wurde es entworfen. Sie haben Java als Gegenbeispiel erwähnt - die Java-Sprachdesigner wollten das Laden von Klassen etwas implizit machen, damit sie vor dem Werfen dasselbe Verzeichnis überprüfen ClassNotFound. Abgesehen davon müssen Sie sich qualifizieren, genau wie in Python.

Wie Tom Anderson sagte, macht C dasselbe wie Python und es ist eine kompilierte Sprache. Vielleicht hatte die interpretierte Natur der Sprache etwas mit der endgültigen Entscheidung zu tun (für Leistung, Aussagekraft usw.), aber am Ende liegt es am Entwickler.

Michael K.
quelle
Ich bin mir nicht sicher, ob "so wurde es entworfen" wirklich eine Antwort auf diese Frage ist.
Winston Ewert
2
-1: Ich weiß , Python nicht gut, aber mein Verständnis ist , dass Sie haben ein Paket zu verwenden alles in es in Python zu importieren. In Java müssen Sie technisch gesehen keine Importanweisungen verwenden. Sie können einfach die vollständigen, qualifizierten Namen von Klassen usw. in andere Pakete schreiben.
Compman
1
Bei der Qualifizierung wird der Pfad zu einem Objekt (Klasse, Funktion usw.) aufgelöst. Ob dies durch Importe oder Syntaxqualifizierer erfolgt, spielt keine Rolle.
Michael K
3

Da Python interpretiert wird, ist alles, was Sie importieren, an der Eingabeaufforderung verfügbar. Java (und C ++) verfügen über einen Kompilierungs- und Verknüpfungsschritt, der nur verwendete Funktionen suchen und enthalten kann

Wenn alles automatisch importiert würde, gäbe es Tausende von Funktionen und Variablen, und es wäre unmöglich, etwas einzugeben, ohne mit einer zu kollidieren.

edit: Ok, es ist ein bisschen mehr als nur kompiliert oder interpretiert. Python ist als "Batterien enthalten" -Sprache gedacht - es stehen Bibliotheken zur Verfügung, um fast alles zu tun. Da Sie immer nur einen kleinen Teil davon verwenden werden, muss es eine Möglichkeit geben, sie so zu organisieren, dass Sie nur diejenigen einbeziehen, die Sie benötigen.

Der Import aus der Syntax ist clever, da Sie entweder die gesamte Bibliothek importieren und Java-ähnliche, vollständig qualifizierte Namen beibehalten oder bestimmte Funktionen (oder alle Funktionen) in den lokalen Namespace importieren können

>>>import math
>>> math.sin(0)  #no confusion with any other 'sin'

>>> from math import sin  # or import *
>>> sin(0) # makes equations with sin shorter and simpler

Der zweite Grund ist besonders wichtig in einer dynamischen Sprache wie Python. Da Sie keine Variablen definieren müssen, bevor Sie sie verwenden, ist es für die Umgebung schwierig herauszufinden, ob sindie mathematische Funktion oder eine Ihrer Variablen in einem Interpreter vorhanden ist.

Martin Beckett
quelle
Ich verstehe es nicht ... Könnten Sie es einem Neuling erklären? :(
Chuck Testa
@ChuckTesta Um den in dieser Antwort diskutierten Unterschied vollständig zu verstehen, müssen Sie den Unterschied zwischen kompilierten und interpretierten Sprachen verstehen - dieser Blog-Beitrag fasst es ganz einfach zusammen: blog.julipedia.org/2004/07/…
Bob
8
Der Unterschied hat absolut nichts mit interpretiert oder kompiliert zu tun. Sie könnten einen Python-Compiler schreiben und müssten genauso arbeiten wie der Python-Interpreter. Der Unterschied besteht einfach darin, dass die Designer von Java (sagen wir) beschlossen haben, das implizite Laden von Klassen aus anderen Dateien hinzuzufügen, und die Designer von Python nicht. Beachten Sie, dass C kompiliert ist, aber im Wesentlichen dieselben Regeln wie Python hat. Sie können eine Funktion aus einer anderen Datei nur verwenden, wenn Sie einen # Header dafür einschließen und die richtige Bibliothek verknüpfen.
Tom Anderson
2
Der Punkt ist gültig: implizites Laden von Klassen würde in einer interpretierten Sprache
hohe
1
@ Simon, warum sollte es große Laufzeitkosten haben?
Winston Ewert
1

Stellen Sie sich vor, Sie hätten diesen Code in Python:

foo = MyObject()
fo.bar()

Offensichtlich haben wir einen Tippfehler und fohätten es tun sollen foo. Im Moment sagt Python:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fo' is not defined

Aber beim impliziten Laden von Klassen könnte es heißen:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named fo

das wäre verwirrend. Schlimmer noch, wenn Sie einen Variablennamen falsch geschrieben haben, der zufällig der Name eines Moduls ist, wird ein noch verwirrenderer Fehler angezeigt, wenn Sie versuchen, dieses Modul so zu behandeln, als wäre es Ihre Variable. Python kann nicht sagen, ob etwas ein Klassenname, ein Objekt oder was auch immer ist.

Java hingegen kann meiner Meinung nach anhand der Syntax erkennen, ob sich ein bestimmter Bezeichner auf eine Klasse oder etwas anderes bezieht. Somit ist es kein Problem, eine entsprechende Fehlermeldung zu erzeugen.

Insgesamt passt es in die Python-Philosophie, eher explizit als implizit zu sein. Sie finden es besser, ein Modul explizit zu importieren, als es automatisch importieren zu lassen. Das Problem der Fehlermeldung ist ein Faktor, der bei der Entscheidung eine Rolle spielt.

Einige haben vorgeschlagen, dass implizite Importe hohe Laufzeitkosten verursachen würden. Das glaube ich nicht. Was passiert, ist ungefähr so:

  1. LOAD_GLOBAL Opcode mit dem Namen "foo" aufgerufen
  2. globales Wörterbuch auf "foo" geprüft
  3. Eingebautes Wörterbuch auf "foo" geprüft
  4. Wenn foo gefunden wurde, lagern Sie es in Globals und fahren Sie fort
  5. Wenn foo nicht gefunden wird, lösen Sie NameError aus

Um das implizite Laden von Modulen zu unterstützen, können wir Folgendes tun:

  1. LOAD_GLOBAL Opcode mit dem Namen "foo" aufgerufen
  2. globales Wörterbuch auf "foo" geprüft
  3. Eingebautes Wörterbuch auf "foo" geprüft
  4. Wenn dies fehlschlägt, versuchen Sie es import foo
  5. Wenn foo gefunden wurde, lagern Sie es in Globals und fahren Sie fort
  6. Wenn foo nicht gefunden wird, lösen Sie NameError aus

Bei der ersten Verwendung des Moduls dauert es etwas länger, da zuerst andere Wörterbücher durchsucht werden müssen. Dies ist jedoch nur das erste Mal und sollte für die gesamte Programmlaufzeit nicht von Bedeutung sein.

Bei falsch geschriebenen Variablennamen würden erhebliche Kosten entstehen. Wenn sie auftreten, verschwendet Python Zeit damit, die Festplatte zu lesen und zu versuchen, das Modul zu finden. Aber wenn das passiert, wird Ihr Programm sowieso mit einem Traceback sterben und die Leistung ist kein großes Problem.

Winston Ewert
quelle
1

Es gibt einige wichtige Unterschiede zwischen Python und Java. Während Java eine Regel "eine Klasse pro Datei" hat, tut dies Python nicht. Außerdem ist nicht alles in Python eine Klasse.

Ein Modul kann also Klassen, Funktionen und einfach nur alte Variablen enthalten - normalerweise alle in irgendeiner Weise miteinander verbunden (z. B. Zufallsfunktionen in random, mathematische Routinen in math, Zeichenfolgenkonstanten in stringusw.).

Wenn Sie von einem bestimmten Modul aus auf Klassen / Funktionen / Variablen zugreifen möchten, müssen Sie diese zuerst importieren.

Warum ist das eine gute Sache?

  • Hält die Namensräume der Module sauber (nicht überfüllt mit Namen, die Sie niemals verwenden werden)
  • Es ist einfacher, zum entsprechenden Modul zurückzukehren, wenn etwas schief geht
  • Ermöglicht es Ihnen, Namen zu verwenden, ohne einen Fehler befürchten zu müssen, weil der Name verwendet wird, oder den bereits verwendeten Namen zu überfallen (Sie können math.sinund Ihre eigenen sinFunktionen haben).
  • Hilft bei der Klärung der Programmstruktur.
Ethan Furman
quelle
1

Eines der wichtigsten Konzepte in Python ist das von Namespaces (machen Sie import thisan der Eingabeaufforderung einige Zeit, um herauszufinden, was die anderen sind). Ich weiß, dass Namespaces auch in anderen Sprachen existieren, aber in Python haben Sie nur Zugriff auf den aktuellen Namespace, der im aktuellen Modul definiert ist. Um Zugriff auf andere Bezeichner zu erhalten, müssen Sie diese in den aktuellen Namespace importieren: entweder durch Importieren des enthaltenen Moduls (der import fooSyntax) oder der Namen selbst ( from foo import bar).

Daniel Roseman
quelle