據我理解,上下文管理的__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
你很困惑*創建一個上下文管理器和輸入上下文。這兩者是截然不同的,您可以多次使用相同的上下文管理器。 –