2013-04-08 7 views
11

Ich lerne Python und bin immer noch ein Anfänger, obwohl ich es seit etwa einem Jahr studiere. Ich versuche, ein Modul von Funktionen zu schreiben, das innerhalb eines Hauptmoduls aufgerufen wird. Jede der Funktionen im aufgerufenen Modul benötigt das Mathematik-Modul zum Ausführen. Ich frage mich, ob es eine Möglichkeit gibt, dies zu tun, ohne das Mathematikmodul in das aufgerufene Modul zu importieren. Hier ist, was ich habe:Python: Namespaces mit Modul Imports

main.py:

from math import * 
import module1 

def wow(): 

    print pi 


wow() 
module1.cool() 

module1.py:

def cool(): 

    print pi 

Wenn main.py läuft ich:

3.14159265359 

Traceback (most recent call last): 
    File "Z:\Python\main.py", line 10, in <module> 
    module1.cool() 
    File "Z:\Python\module1.py", line 3, in cool 
    print pi 
NameError: global name 'pi' is not defined 

Was ich habe eine harte Zeit zu verstehen, mit Deshalb erhalte ich einen Namensfehler beim Ausführen von main.py. Ich weiß, dass die Variable pi beim Import global zum Hauptmodul wird, weil wow darauf zugreifen kann. Ich weiß auch, dass cool beim Import global zum Hauptmodul wird, weil ich module1.cool drucken und <function cool at 0x02B11AF0> bekommen kann. Also, da cool im globalen Namespace des Hauptmoduls ist, sollte das Programm nicht zuerst in die Funktion cool für die Variable pi schauen und dann, wenn es dort nicht gefunden wird, in das Modul main für die Variablen pi und schauen finde es da?

Die einzige Möglichkeit, das zu umgehen, die ich kenne, ist das Importieren des Mathematikmoduls in module1.py. Ich mag die Idee nicht, obwohl es die Dinge komplizierter macht und ich ein Fan von nettem, einfachem Code bin. Ich habe das Gefühl, dass ich Namespaces nahe bin, aber brauche Hilfe in diesem Bereich. Vielen Dank.

Antwort

16

Wie die Rückverfolgung zeigt, ist das Problem nicht in main.py, aber in module1.py:

Traceback (most recent call last): 
    File "Z:\Python\main.py", line 10, in <module> 
    module1.cool() 
    File "Z:\Python\module1.py", line 3, in cool 
    print pi 
NameError: global name 'pi' is not defined 

Mit anderen Worten, in module1, gibt es keinen globalen Namen pi, weil Sie nicht importiert es dort.Wenn Sie from math import * in main.py tun, importiert das alles aus dem math Modul-Namespace in den main Modul-Namespace, nicht in alle Modul Namespace.

Ich denke, das Wichtigste, was Sie hier vermissen, ist, dass jedes Modul seinen eigenen "globalen" Namensraum hat. Dies kann zunächst etwas verwirrend sein, da in Sprachen wie C ein einzelner globaler Namespace von allen extern Variablen und Funktionen gemeinsam genutzt wird. Aber sobald man diese Annahme überwunden hat, macht der Python-Weg durchaus Sinn.

Also, wenn Sie pi von module1 verwenden möchten, müssen Sie die from math import * in module1.py tun. (Oder Sie könnten einen anderen Weg finden, um zu injizieren es, zum Beispiel module1.pyfrom main import * tun könnte, oder main.pymodule1.pi = pi tun könnte, usw. Oder Sie könnten pi in die magischen builtins/__builtin__ Modul stopfen oder verschiedene andere Tricks anwenden. Aber die offensichtlichen Lösung ist die import zu tun, wo Sie es importiert werden sollen.)


Als Randbemerkung, Sie in der Regel nicht wollen from foo import * überall mit Ausnahme der interaktiven Interpreter oder gelegentlich zu tun, der Top-Level-Skript. Es gibt Ausnahmen (z. B. einige Module sind explizit so entworfen, dass sie auf diese Weise verwendet werden können), aber die Faustregel lautet entweder import foo oder verwenden Sie eine begrenzte from foo import bar, baz.

+1

Vielen Dank für die Antwort. Wenn ich dich dann richtig verstehe, wenn ich "cool" in main.py rufe, sucht es zuerst nach pi in cool selbst, aber es nicht zu finden, dann sucht es nach pi in module1.py, _not_ main.py und offensichtlich doesn Ich finde es nicht. Daher ist die Suche nach pi in diesem Fall auf den globalen Namespace von module1 beschränkt und kann nicht auf den globalen Namespace von main1 zugreifen. Ist das richtig? – SpencerAAA

+1

@SpencerAAA: Das ist eine leichte Vereinfachung, aber nur eine kleine, und es ist richtig für alle relevanten Teile. Unter [Benennen und Binden] (http://docs.python.org/2/reference/executionmodel.html#naming-and-binding) finden Sie die vollständigen Details. – abarnert

+1

@SpencerAAA: Eigentlich brauchen Sie ein bisschen mehr als diesen Abschnitt, um alle Details zu erhalten. Kurz gesagt: Zu der Zeit, zu der die 'cool'-Definition ausgewertet wird, bestimmt Python, dass 'pi' nicht lokal ist (das heißt, frei im Bereich der Funktion), und kompiliert die Funktion in etwas wie' print_item (globals() (' pi ')) '. (Wenn Sie CPython-Bytecode verstehen oder zu lernen bereit sind, versuchen Sie 'import dis' und' dis.dis (cool) ', um _exactly_ zu sehen, was es tut.) Dann folgt diese' globals'-Suche den Regeln für globale Suche in Benennung und Bindung. – abarnert

6

"Explizit ist besser als implizit" ist eine Designentscheidung, die von den Erstellern von Python getroffen wurde (starten Sie python und führen Sie import this). Wenn Sie also module1.cool() ausführen, sucht Python nicht nach dem undefinierten pi im main Modul.

Sie müssen das Mathemodul explizit importieren, wann immer Sie es verwenden möchten - so funktioniert Python.

Auch sollten Sie vermeiden from X import *-Stil Importe, das ist auch schlechte Übung. Hier könnten Sie tun: from math import pi.

1

Innerhalb des Moduls können Sie einfach from math import pi definieren, die nur Pi aus Mathematik, aber nicht das gesamte Mathematikmodul importieren würde.

2

Wie andere gesagt haben, gibt es in Ihrer module1 keinen globalen pi. Eine gute Lösung für Sie ist das, was nur einmal pi von math und ausdrücklich stellt sicher, dass die pi Sie bekommen ist die von module1 importiert:

main.py:

import module1 

def wow(): 
    print module1.pi 

wow() 
module1.cool() 

module1.py:

from math import pi 

def cool(): 
    print pi