Сужение типов, которое происходит после if
или assert
, не распространяется на внутренние области, в которых вы связали эту переменную. Простой обходной путь - определить новую переменную, связанную с более узким типом, Например:
def bar() -> None:
d = foo(False)
if not d:
return
d_exists = d
filter(lambda x: d_exists['k'], [])
Причина, по которой d
не привязан к более узкому типу во внутренней области видимости, может заключаться в том, что нет гарантии того, что d
может не измениться на None
в внешняя область действия, например:
def bar() -> None:
d = foo(False)
if not d:
return
def f(x: str) -> str:
assert d is not None # this is totally safe, right?
return d['k'] # mypy passes because of the assert
d = None # oh no!
filter(f, [])
, тогда как если вы связываете новую переменную, это присвоение невозможно:
def bar() -> None:
d = foo(False)
if not d:
return
d_exists = d
def f(x: str) -> str:
# no assert needed because d_exists is not Optional
return d_exists['k']
d_exists = None # error: Incompatible types in assignment
filter(f, [])
В вашем конкретном примере нет опасности во время выполнения, потому что lambda
оценивается немедленно filter
, и у вас нет шансов изменить d
в то же время, но у mypy не всегда есть простой способ определить, что вызванная вами функция не собирается зависать от этой лямбды и оценивать это позже.