2014-08-28 1 views
6

Ich habe den folgenden Code gefangen ausgeführt:Exception wird zweimal und es wird von einem anderen außer Block

file1.py

from file2 import tfun 

class TestException(Exception): 
    pass 

try: 
    print 'I am running' 
    tfun() 
except TestException as e: 
    print 'I am caught' 
    print type(e) 
except Exception as e: 
    print 'I am generally caught' 
    print type(e) 

file2.py

def tfun(): 
    from file1 import TestException 
    raise TestException() 

und die Ausgabe von python file1.py ist die folgende:

I am running 
I am running 
I am caught 
<class 'file1.TestException'> 
I am generally caught 
<class 'file1.TestException'> 

Vor allem warum der Code in diesem Fall zweimal ausgeführt wird? Ich kann verstehen, dass der Import rekursiv ist, aber warum der Code des Skripts erneut ausgeführt wird?

Zweitens, das zweite Mal wird es nicht durch den gleichen except Block gefangen, obwohl es den gleichen Typ wie das erste Mal ist, für die ich auch keine Erklärung finden kann.

Schließlich versuche ich, eine Problemumgehung für dieses Problem zu finden, ohne etwas zu einer neuen Datei zu verschieben, aber ich scheint es nicht zu sein. Ist es möglich, dieses Problem zu überwinden?

bearbeiten

Für die zweite Frage wurde mir klar, es liegt daran, dass der Code innerhalb der Modulebene ist.

+3

+1 für ein kurzes, vollständiges, eigenständiges Programm, das das vorliegende Problem aufzeigt. Ref: http://Stackoverflow.com/help/mcve und http://SSCCE.org –

Antwort

7

Wenn Sie ein Modul als Skript ausgeführt (das heißt gibt ihren Namen den Dolmetscher, anstatt sie zu importieren), ist es unter dem Modulnamen __main__ geladen.

Wenn Sie dann das gleiche Modul aus Ihrem Programm importieren, wird es neu geladen und unter seinem echten Namen erneut ausgeführt. Wenn Sie nicht vorsichtig sind, können Sie am Ende Dinge zweimal tun.

http://effbot.org/zone/import-confusion.htm

Sie Laden file1.py zweimal, als zwei verschiedene Module. Das erste Mal, es als reesult der Befehlszeile geladen wird:

python file1.py 

In diesem Fall wird file1.py als Hauptmodul geladen, __main__.

Das zweite Mal, wenn Sie es als Ergebnis Ihrer Import-Anweisung laden:

from file1 import TestException 

In diesem Fall wird file1.py als file1 Modul geladen wird.

Da file1.py als zwei verschiedene Module geladen wird, gibt es zwei verschiedene Kopien von allem darin. Insbesondere unterscheidet sich __main__.TestException von file1.TestException.

also innerhalb __main__, die Zeile:

except TestException as e: 

holt __main__.TestException auch als tfun() ist __file1__.TestException erhöhen. Innerhalb file1 fängt dieselbe Linie file1.TestException ein. Im ersten Fall stimmen die Typen nicht überein und die except:-Klausel wird nicht ausgeführt. Im letzteren Fall stimmt der Typ überein und die except:-Klausel wird ausgeführt.

Vielleicht kann dieses Programm macht es klar, was passiert:

from file2 import tfun 

class TestException(Exception): 
    pass 

try: 
    print 'I am calling file2.tfun from', __name__ 
    tfun() 
    print 'I have called file2.tfun from', __name__ 
except TestException as e: 
    print 'I am caught in %s'%(__name__) 
    print type(e), TestException 
except Exception as e: 
    print 'I am generally caught in %s'%__name__ 
    print type(e), TestException 
print 'I am exiting from',__name__ 

Ergebnis:

$ python file1.py 
I am calling file2.tfun from __main__ 
I am calling file2.tfun from file1 
I am caught in file1 
<class 'file1.TestException'> <class 'file1.TestException'> 
I am exiting from file1 
I am generally caught in __main__ 
<class 'file1.TestException'> <class '__main__.TestException'> 
I am exiting from __main__ 

Eine einfache Abhilfe file2.py zu ändern ist:

def tfun(): 
    from __main__ import TestException 
    raise TestException() 

Ergebnis :

$ python file1.py 
I am calling file2.tfun from __main__ 
I am caught in __main__ 
<class '__main__.TestException'> <class '__main__.TestException'> 
I am exiting from __main__ 
+2

+1 Der Unterschied zwischen '__main __. TestException' und' file1.TestException' ist der schwierigste Teil, denke ich. – chepner

Verwandte Themen