Python 内置对象的 __enter__() 和 __exit__() 定义在哪里?

问题描述 投票:0回答:4

我读到每次使用“with”时都会调用对象的 __enter__() 和 __exit__() 方法。我知道对于用户定义的对象,您可以自己定义这些方法,但我不明白这对于内置对象/函数(如“open”)甚至测试用例是如何工作的。

此代码按预期工作,我假设它使用 __ exit__() 关闭文件:

with open('output.txt', 'w') as f:
    f.write('Hi there!')

with self.assertRaises(ValueError):
    remove_driver(self.driver)  # self refers to a class that inherits from the default unittest.TestCase

然而,当我检查它时,两个对象上都没有这样的 __ Enter__() 或 __ exit__() 方法:

enter image description here

enter image description here

那么“open”如何与“with”一起使用呢?支持上下文管理协议的对象不应该定义和检查 __ Enter__() 和 __ exit__() 方法吗?

python with-statement contextmanager code-inspection
4个回答
11
投票

open()
是一个函数。 它返回具有
__enter__
__exit__
方法的东西。 看看这样的东西:

>>> class f:
...     def __init__(self):
...         print 'init'
...     def __enter__(self):
...         print 'enter'
...     def __exit__(self, *a):
...         print 'exit'
... 
>>> with f():
...     pass
... 
init
enter
exit
>>> def return_f():
...     return f()
... 
>>> with return_f():
...     pass
... 
init
enter
exit

当然,

return_f
本身没有这些方法,但是它返回的有。


6
投票

open
是一个使用上下文方法返回文件对象的函数,
self.assertRaises
是一个使用上下文方法返回对象的方法,尝试检查它们的返回值的
dir

>>> x = open(__file__, "r")
>>> x
<_io.TextIOWrapper name='test.py' mode='r' encoding='US-ASCII'>
>>> type(x)
<class '_io.TextIOWrapper'>
>>> "__exit__" in dir(x)
True

2
投票

您正在检查

open
函数本身或
assertRaises
方法本身是否具有
__enter__
__exit__
方法,而您应该查看返回值有哪些方法。


0
投票

当您打开文本文件进行读取时,该函数返回 TextIOWrapper 类的实例。

textio.c源代码我们可以看到类树是:

IOBase <- TextIOBase <- TextIOWrapper

IOBase定义了__enter__和__exit__函数,并在__exit__函数中调用close()。

TextIOWrapper类从IOBase继承这些方法,并使“with”语句起作用。

© www.soinside.com 2019 - 2024. All rights reserved.