exc_value parameter from __exit__() (context manag

2019-08-10 21:19发布

问题:

I tried to mess around with context managers and got a bit surprised when running my code with Python 2.6. Indeed, the exc_value parameter seems to be a string instead of an exception.

A bit of code to hi-light this issue :

import sys

class contextmanager(object):

    def __enter__(self):
        pass

    def __exit__(self, type_, value, traceback):
        assert (type_ is None) == (value is None)
        if value is not None:
            print(type(value))


if __name__ == '__main__':
    print(sys.version_info)
    with contextmanager():
        __name_ # should trigger name exception

With Python 2.7 :

<type 'exceptions.NameError'>                       # GOOD
Traceback (most recent call last):
  File "test_conman.py", line 17, in <module>
    __name_
NameError: name '__name_' is not defined

With Python 3.2 :

sys.version_info(major=3, minor=2, micro=3, releaselevel='final', serial=0)
<class 'NameError'>                       # GOOD
Traceback (most recent call last):
  File "test_conman.py", line 17, in <module>
    __name_
NameError: name '__name_' is not defined

With Python 2.6 :

(2, 6, 7, 'final', 0)
<type 'str'>                       # BAD
Traceback (most recent call last):
  File "test_conman.py", line 17, in <module>
    __name_
NameError: name '__name_' is not defined

My understanding is that exc_value should always be an exception. Is there anything I did wrong ? Is there anything I misunderstood ? Is this a known issue ?

References

  • What’s New in Python 2.6 : PEP 343: The with statement

  • Python 2 docs : object.__exit__(self, exc_type, exc_value, traceback)

回答1:

This was a bug in Python 2.6, see issue 7853. It was fixed for Python 2.7a3 but never backported to the 2.6 branch.

In other words, you did nothing wrong, Python did.

Unfortunately, there's no real work-around other than to handle the fact that you don't have an exception instance in 2.6 but only the string value.