英文:
(How) can I make a decorator narrow a type in the function body?
问题
我正在实现一个装饰器来替代重复的早期退出检查,例如:
if self.data is None:
self.log_something()
return
这个装饰器 @early_exit_if(data_is_none)
确保在 do_something_with_data
方法体内,data
不是 None
。但是,mypy
并不知道这一点。
如何让 mypy
知道(最好是从装饰器内部)data
不会是 None
?
我知道 assert self.data is not None
可以工作,但我不喜欢重复这个检查。
编辑:我刚刚了解到 TypeGuard
,我想知道这种方法是否可以与装饰器结合使用。
英文:
I am implementing a decorator to replace repeated early-exit checks such as
if self.data is None:
self.log_something()
return
at the top of my methods. This approach (highly simplified here) does work nicely:
"""early exit decorator."""
from collections.abc import Callable
Method = Callable[["Class"], None]
Condition = Callable[["Class"], bool]
def early_exit_if(condition: Condition) -> Callable[[Method], Method]:
def decorator(method: Method) -> Method:
def wrapper(instance: "Class") -> None:
if condition(instance):
return
method(instance)
return wrapper
return decorator
class Class:
def __init__(self) -> None:
self.data: list[int] | None = None
@staticmethod
def data_is_none(instance: "Class") -> bool:
return instance.data is None
@early_exit_if(data_is_none)
def do_something_with_data(self) -> None:
self.data.append(0)
if __name__ == "__main__":
Class().do_something_with_data()
In short, @early_exit_if(data_is_none)
ensures that data
is not None
in the body of do_something_with_data
. However, mypy
does not know that:
> bug.py:30: error: Item "None" of "list[int] | None" has no attribute "append" [union-attr]
How can I let mypy
know (ideally, from within the decorator) that data
is not None
?
I know that assert self.data is not None
works, but I dislike duplicating the check.
Edit: I just learned about TypeGuard
s, and I wonder if this approach can be combined with decorators.
答案1
得分: 1
Here is the translated content:
实际上,您可能已经有了最佳答案:
assert self.data is not None
这在mypy类型缩小等方面有很好的文档支持。
请记住,这并不一定会重复检查,因为assert通常用于开发阶段,在生产中,您可以运行“python -O”(优化模式),断言将被忽略,因此不会影响性能。
英文:
Actually, you may already have the best answer:
assert self.data is not None
Is well documented by mypy in type narrowing among other things.
Remember that it doesn't necessarily duplicate the check as assert is meant to be use mostly at development time, in production you can run "python -O" (optimized mode) and asserts are just ignored, so it doesn't impact performance at all.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论