TL, DR : Chování není stejný pro oba konstrukty, i když by být zřetelné rozdíly mezi příklady 2.
Měli byste se téměř nikdy potřebovat :=
v with
prohlášení, a někdy je to velmi špatné. V případě pochybností, vždy with ... as ...
když budete potřebovat spravovaný objekt uvnitř with
bloku.
V roce with context_manager as managed
, managed
je vázán na návratovou hodnotu z context_manager.__enter__()
, zatímco v with managed := context_manager
, managed
se váže na context_manager
sebe a návratová hodnota __enter__()
volání metody je zlikvidovat . Chování je téměř shodné pro otevřené soubory, protože jejich __enter__
metoda vrací self
.
První výňatek zhruba analogická
_mgr = (f := open('file.txt')) # `f` is assigned here, even if `__enter__` fails
_mgr.__enter__() # the return value is discarded
exc = True
try:
try:
BLOCK
except:
# The exceptional case is handled here
exc = False
if not _mgr.__exit__(*sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
_mgr.__exit__(None, None, None)
k tomu, že as
forma bude
_mgr = open('file.txt') #
_value = _mgr.__enter__() # the return value is kept
exc = True
try:
try:
f = _value # here f is bound to the return value of __enter__
# and therefore only when __enter__ succeeded
BLOCK
except:
# The exceptional case is handled here
exc = False
if not _mgr.__exit__(*sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
_mgr.__exit__(None, None, None)
tedy with f := open(...)
by se nastaven f
na návratovou hodnotu open
, přičemž with open(...) as f
se váže f
na návratovou hodnotu implicitní __enter__()
volání metody.
Nyní, v případě, že soubory a potoků , file.__enter__()
vrátí self
-li se to podaří, tak chování těchto dvou přístupů je téměř stejný - rozdíl je pouze v případě, že __enter__
způsobí výjimku.
Skutečnost, že přiřazení výrazy se často pracují místo as
je ošidná, protože existuje mnoho tříd, kde _mgr.__enter__()
se vrací objekt, který je odlišný od self
. V tomto případě výraz přiřazení funguje jinak: kontextové manager přiřazen namísto řízeného objektu . Například unittest.mock.patch
je kontext manažer, který vrátí falešný objekt. V dokumentaci k němu má následující příklad:
>>> thing = object()
>>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing:
... assert thing is mock_thing
... thing()
...
Traceback (most recent call last):
...
TypeError: 'NonCallableMock' object is not callable
Teď, když to bylo být psán používat výraz přiřazení chování by bylo něco jiného:
>>> thing = object()
>>> with mock_thing := patch('__main__.thing', new_callable=NonCallableMock):
... assert thing is mock_thing
... thing()
...
Traceback (most recent call last):
...
AssertionError
>>> thing
<object object at 0x7f4aeb1ab1a0>
>>> mock_thing
<unittest.mock._patch object at 0x7f4ae910eeb8>
mock_thing
Nyní je vázán na kontextu správce namísto nového makety objektu.