我有一个函数
original
,带有指定的参数、它们的类型和文档字符串。
我如何定义一个函数
new
,它基本上会调用original
,但用一些a
值覆盖A_DEFAULT
参数。例如。 new(x) == original(A_DEFAULT, x)
。
最重要的部分是由此产生的
new
a
参数目标是在不显式复制原始文档字符串和签名的情况下制作此类部分函数。
有什么想法可以做到吗? (即使你有一些古怪的想法)
import functools
A_DEFAULT = ...
def original(a: int, b: str):
"description"
return a + b
# `new` should have in IDE tooltips and type checks:
# - __doc__ = "description"
# - signature = (b: int)
# new(x) = original(A_DEFAULT, x)
new = ...
以下解决方案基于此示例此处。对于包括文档字符串在内的静态类型行为,
Concatenate
和 ParamSpec
证明是有用的:
from typing import Callable, Concatenate, ParamSpec, TypeVar
def original(a: int, b: str):
"description"
return str(a) + b
P = ParamSpec("P")
R = TypeVar("R")
T = TypeVar("T")
def set_first_arg_default(
f: Callable[Concatenate[T, P], R],
first_arg_default: T
) -> Callable[P, R]:
def inner(*args: P.args, **kwargs: P.kwargs) -> R:
return f(first_arg_default, *args, **kwargs)
return inner
A_DEFAULT = 1
new = set_first_arg_default(original, A_DEFAULT)
print(new("x"))
如果您还需要在运行时更新文档字符串和签名,可以使用
inspect
库来修改__signature__
。我将这个示例分开,因为它使解决方案更加复杂:
from typing import Callable, Concatenate, ParamSpec, TypeVar
import inspect
def original(a: int, b: str):
"description"
return str(a) + b
P = ParamSpec("P")
R = TypeVar("R")
T = TypeVar("T")
def set_first_arg_default(
f: Callable[Concatenate[T, P], R],
first_arg_default: T
) -> Callable[P, R]:
def get_new_signature(
f: Callable[Concatenate[T, P], R]
) -> inspect.Signature:
old_sig = inspect.signature(f)
params = list(dict(old_sig.parameters).values())
return old_sig.replace(parameters=params[1:])
def inner(*args: P.args, **kwargs: P.kwargs) -> R:
return f(first_arg_default, *args, **kwargs)
# This section is optional as far as IDEs are concerned
inner.__doc__ = f.__doc__
inner.__signature__ = get_new_signature(f) # type: ignore reportFunctionMemberAccess
return inner
A_DEFAULT = 1
new = set_first_arg_default(original, A_DEFAULT)
print(new("x"))
help(new)