为什么在带块的Python中无法调用可调用的?

时间:2017-01-19 19:15:33

标签: python with-statement callable

为什么可调用的内容在Python 3.5 with语句中无法调用的任何押韵或原因?

class Seriously(object):
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print("Enter " + self.name)

    def __call__(self):
        print("Call " + self.name)

    def __exit__(self, type, value, traceback):
        print("Exit " + self.name)

a = Seriously('a')
a.__enter__()
a()
a.__enter__()

with Seriously('b') as b:
    b()

认真生产

Enter a
Call a
Enter a
Enter b
Exit b
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-91a5d11e1b2e> in <module>()
     18 
     19 with Seriously('b') as b:
---> 20     b()

TypeError: 'NoneType' object is not callable

我在PEP 343中遗漏了什么?

2 个答案:

答案 0 :(得分:4)

您不会从__enter__方法返回任何内容,该方法由python编译器转换为None的返回值。您应该从as返回__enter__子句绑定的值。

with语句被视为

mgr = (EXPR)
exit = type(mgr).__exit__ 
value = type(mgr).__enter__(mgr)  ### <--- usually the same as mgr.__enter__()
exc = True
try:
    try:
        VAR = value               ### <--- value returned by __enter__, VAR from with/as statement
        BLOCK
    except:
        exc = False
        if not exit(mgr, *sys.exc_info()):
                raise
finally:
    if exc:
        exit(mgr, None, None, None)

(来自您在问题中链接的PEP)。

答案 1 :(得分:0)

__enter__方法可以显式返回对象(self),构造函数已在__enter__之前调用。您可以直接传递对象或更改它或返回不同的对象。

__exit__方法获取四个参数self,后跟异常类型,值和回溯对象 - 与sys.exc_info()返回的相同。如果没有异常,那么三个异常参数都是None

如果__exit__返回True,则表示该异常已被处理且未传播。返回值False表示没有例外。