Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception gets executed twice and it gets caught by a different except block

I have the following code:

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()

and the output from python file1.py is the following:

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

First of all why the code gets executed twice in this case? I can understand that the import is recursive but why the code of the script get executed again?

Secondly, the second time it is not getting caught by the same except block even though it is the same type as the first time, which also I cannot find an explanation for.

Finally, I am trying to find a workaround for this problem without moving anything to a new file but I it does not seem to be any. Is it possible to get over this problem?

Edit

For the second question I realized it is because the code is inside the module level.

like image 247
zbs Avatar asked Aug 28 '14 13:08

zbs


1 Answers

If you run a module as a script (i.e. give its name to the interpreter, rather than importing it), it’s loaded under the module name __main__.

If you then import the same module from your program, it’s reloaded and reexecuted under its real name. If you’re not careful, you may end up doing things twice.

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

Your are loading file1.py twice, as two distinct modules. The first time it is loaded as a reesult of your command line:

python file1.py

In that case, file1.py is being loaded as the main module, __main__.

The second time you are loading it as a result of your import statement:

from file1 import TestException

In that case, file1.py is being loaded as the module file1.

Because file1.py is being loaded as two distinct modules, there are two distinct copies of everything in it. Particularly __main__.TestException is different from file1.TestException.

So, inside __main__, the line:

except TestException as e:

is catching __main__.TestException even as tfun() is raising __file1__.TestException. Inside file1, that same line is catching file1.TestException.

In the former case, the types do not match and the except: clause is not run; in the latter case the type does match and the except: clause is run.

Perhaps this program can make it more clear what is happening:

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__

Result:

$ 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__

A simple workaround is to modify file2.py:

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

Result:

$ 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__
like image 147
Robᵩ Avatar answered Oct 24 '22 08:10

Robᵩ