Redirecting stderr for extension modules

Jeff Epler jepler at unpythonic.net
Thu May 15 14:15:34 EDT 2003


On Thu, May 15, 2003 at 09:55:16AM -0700, Michael Pyle wrote:
> Hi Jeff,
> 
> Yep, we worked this one out after I sent the email and on Solaris everything
> works a lot better. On Windows, however, nothing ever actually makes it into
> the redirection file.

I don't know enough about Windows to speculate why this might be the
case.  You might actually inspect the exception raised when the setup
of the captured stdout fails, which might be what is happening.

> Just to reiterate a little, so the body of a finally is the absolute last
> thing that is executed? Even after the return values are constructed in the
> return statement?

Yes.  In all these combinations, the numbers output will necessarily be
in ascending order:

try:
    print 1
    f()
except:
    print 2
else:
    print 3

try:
    print 1
    f()
finally:
    print 2

try:
    print 1
    f()
except:
    print 2

If you want to talk about things at the bytecode level, it looks
somewhat like this (for the try/finally case):
>>> def f():
...     try: return g()
...     finally: print 2
... 
>>> dis.dis(f) # running with -O, so no SET_LINENO opcodes
          0 SETUP_FINALLY           11 (to 14)
          3 LOAD_GLOBAL              0 (g)
          6 CALL_FUNCTION            0
          9 RETURN_VALUE        
         10 POP_BLOCK           
         11 LOAD_CONST               0 (None)
    >>   14 LOAD_CONST               1 (2)
         17 PRINT_ITEM          
         18 PRINT_NEWLINE       
         19 END_FINALLY         
         20 LOAD_CONST               0 (None)
         23 RETURN_VALUE        

You can see that the code is executed down to instruction 9
(RETURN_VALUE).  At this point, Python begins resolving any try: blocks,
and finds one that began at instruction 0 and points to instruction 14.
Code starting at 14 is executed until instruction 19 (END_FINALLY) is
reached.  Then the stored return value is actually given to the caller.

If the 'finally' block *also* contains a reached return statement, then
the value of that return statement is used instead:
>>> def f():
...     try: return 1
...     finally: return 2
... 
>>> f()
2
I am guessing that the bytecode interpreter simply stores the value that
RETURN_VALUE received in a (C) local variable, and the second 'return'
statement overwrites the value there (doing correct reference counting,
of course), changing what is ultimately returned from the function.
Personally, I would think of having multiple 'return' statements
executed is bad style, but perhaps there are good uses I'm unaware of.

Jeff





More information about the Python-list mailing list