英文:
How can I write a python decorator for a input function with type hinting?
问题
I'm trying to create the following python decorator for a function with type hint but it doesn't seem to work. It returned None instead of True. What did I do wrong?
def do_nothing(func):
def Inner_Function(*args, **kwargs):
func(*args, **kwargs)
return Inner_Function
@do_nothing
def is_cold(name: str) -> bool:
return True
g = is_cold("hi")
print(g)
# >> None
英文:
I'm trying create the following python decorator for a function with type hint but it doesn't seem to work. It returned None instead of True. What did I do wrong?
def do_nothing(func):
def Inner_Function(*args, **kwargs):
func(*args, **kwargs)
return Inner_Function
@do_nothing
def is_cold(name: str) -> bool:
return True
g = is_cold("hi")
print(g)
>> None
答案1
得分: 1
要修复你的装饰器的实际运行行为,内部函数需要return原始函数的调用结果:
def do_nothing(func):
def Inner_Function(*args, **kwargs):
return func(*args, **kwargs)
return Inner_Function
@do_nothing
def is_cold(name: str) -> bool:
return True
g = is_cold("hi")
print(g) # True
如果你正在使用类型检查,你会注意到这个装饰器会破坏被装饰函数的类型。如果我们在mypy中检查g的类型,我们会看到它是Any:
g = is_cold("hi")
reveal_type(g) # Revealed type is "Any"
为了解决这个问题,你需要为你的装饰器添加类型提示,以指示它接受一个函数作为参数,并返回相同类型的函数:
from typing import Callable, TypeVar
_Func = TypeVar("_Func", bound=Callable)
def do_nothing(func: _Func) -> _Func:
def Inner_Function(*args, **kwargs):
return func(*args, **kwargs)
return Inner_Function # type: ignore
(你可以为Inner_Function做更复杂的类型提示,以消除# type: ignore的需要,但就@do_nothing装饰器的用户而言,内部发生的事情并不重要,只有do_nothing本身的签名才重要。)
现在is_cold的类型由装饰器保留:
g = is_cold("hi")
reveal_type(g) # Revealed type is "builtins.bool"
英文:
To fix the actual runtime behavior of your decorator, the inner function needs to return the result of calling the original function:
def do_nothing(func):
def Inner_Function(*args, **kwargs):
return func(*args, **kwargs)
return Inner_Function
@do_nothing
def is_cold(name: str) -> bool:
return True
g = is_cold("hi")
print(g) # True
If you're using typechecking, you'll notice that this decorator breaks the typing of the decorated function. If we check the type of g in mypy we'll see that it's Any:
g = is_cold("hi")
reveal_type(g) # Revealed type is "Any"
To fix this, you need to add typing to your decorator to indicate that it takes a function as its argument and returns the same type of function:
from typing import Callable, TypeVar
_Func = TypeVar("_Func", bound=Callable)
def do_nothing(func: _Func) -> _Func:
def Inner_Function(*args, **kwargs):
return func(*args, **kwargs)
return Inner_Function # type: ignore
(You can do more complex typing for Inner_Function to eliminate the need for the # type: ignore, but as far as the users of the @do_nothing decorator are concerned, what happens inside doesn't matter, only the signature of do_nothing itself.)
Now is_cold has its type preserved by the decorator:
g = is_cold("hi")
reveal_type(g) # Revealed type is "builtins.bool"
答案2
得分: 0
InnerFunction 调用 func 但没有返回任何内容。 is_cold 将返回 True,但然后 InnerFunction 将其丢弃,并默认返回 None。
英文:
InnerFunction calls func but doesn't return anything. is_cold will return True, but then InnerFunction tosses that away and, by default, returns None.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论