gaoxinge
gaoxinge

Reputation: 461

`with` statement in python is different from pep343

The code below with with statement runs successfully.

class A(object):

    def __enter__(self):
        return self

    def __exit__(self, et, ev, tb):
        print 1

a = A()

class B(object):

    def __enter__(self):
        return self

    __exit__ = a.__exit__

b = B()

# ok here, without any error
with b:
    print 2

However, if we translate with statement into the code based on pep343, there will be an error.

import sys

mgr   = b
exit  = type(mgr).__exit__
value = type(mgr).__enter__(mgr)
exc   = True
try:
    try:
        print 1
    except:
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
finally:
    if exc:
        exit(mgr, None, None, None)

Because type(b).__exit__(a, None, None, None) equals A.__exit__(a, a, None, None, None), the error is caused by too many parameters.

My question is

Upvotes: 0

Views: 84

Answers (1)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251041

The reason you're getting this error is that you're assigning an instance method from A to B's __exit__, this results in too many arguments because you're passing the instance again with exit: exit(mgr, None, None, None), and it being a bound method, it will append the instance again resulting in too many arguments.

Hence, you can get rid of mgr argument from the exit calls.

Based on your code:

In [21]: B.__exit__.__self__
Out[21]: <__main__.A at 0x110bb65d0>

In [22]: A.__exit__.__self__
Out[22]: None

Upvotes: 1

Related Questions