据我理解,上下文管理的__init__()
和__enter__()
方法被调用一次每一个,一个又一个,不留下任何机会,任何其他代码之间执行。
而你的理解是不正确的。当创建对象时调用__init__
,当它与with
语句一起输入时,它们是__enter__
,这些是2个完全不同的东西。通常情况下,构造函数在with
初始化中直接调用,不需要插入代码,但不一定是这种情况。
考虑这个例子:
class Foo:
def __init__(self):
print('__init__ called')
def __enter__(self):
print('__enter__ called')
return self
def __exit__(self, *a):
print('__exit__ called')
myobj = Foo()
print('\nabout to enter with 1')
with myobj:
print('in with 1')
print('\nabout to enter with 2')
with myobj:
print('in with 2')
myobj
可以单独被初始化,并在多个输入with
块:
输出:
__init__ called
about to enter with 1
__enter__ called
in with 1
__exit__ called
about to enter with 2
__enter__ called
in with 2
__exit__ called
此外如果__init__
和__enter__
不分离,甚至不可能使用以下内容:
def open_etc_file(name):
return open(os.path.join('/etc', name))
with open_etc_file('passwd'):
...
因为初始化(在open
之内)明显与with
分开。
通过contextlib.manager
创建的管理者单入的,但它们可以再次将with
块外构造。就拿例如:
from contextlib import contextmanager
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
您可以使用此为:
def heading(level=1):
return tag('h{}'.format(level))
my_heading = heading()
print('Below be my heading')
with my_heading:
print('Here be dragons')
输出:
Below be my heading
<h1>
Here be dragons
</h1>
但是,如果你尝试重用my_heading
(因而,tag
),你将得到
RuntimeError: generator didn't yield
你很困惑*创建一个上下文管理器和输入上下文。这两者是截然不同的,您可以多次使用相同的上下文管理器。 –