I have a function like this:
我有一个这样的函数:
def foo(*, x: bool, **kwargs: int) -> None:
...
If there is an argument x
, it must be a bool
. Any other named argument must be an int
.
如果有参数x,则它一定是布尔值。任何其他命名参数必须为int。
Other people will write functions that call foo
, and I would like them to be able to pass along x
and the kwargs
. Currently, that means that every function which calls foo()
will have to explicitly pass x
, in addition to the kwargs
, like this:
其他人将编写调用foo的函数,我希望他们能够传递x和kwargs。目前,这意味着调用foo()的每个函数除了kwargs外,还必须显式传递x,如下所示:
def f(a: str, b: str, x: bool, **kwargs: int) -> None:
print(a + b)
foo(x=x, **kwargs)
What I would like to do is define a type for the **kwargs
which makes it unnecessary to explicitly specify x
in each of the functions.
我想要做的是为**kwargs定义一个类型,这使得没有必要在每个函数中显式指定x。
Using Unpack
gets part of the way there, but Unpack
requires all names to be known and listed in the TypedDict
. The code below doesn't work, but I wish I could do something like this, where _other_
magically means any name that's not listed above in the TypedDict
:
使用Unpack在一定程度上实现了这一点,但Unpack要求所有名称都是已知的,并在TyedDict中列出。下面的代码不起作用,但我希望我可以这样做,其中_Other_神奇地表示上面没有在TyedDict中列出的任何名称:
class FooKwargs(TypedDict):
x: bool
_other_: int
def foo(**kwargs: Unpack[FooKwargs]) -> None:
...
def f(a: str, b: str, **kwargs: Unpack[FooKwargs]) -> None:
print(a + b)
foo(**kwargs)
Another possibility that I wish would work is something like this, but it doesn't work because Unpack
only accept TypedDict
s -- it won't accept a Union
, or a dict[str, int]
:
我希望工作的另一种可能性是这样的,但它不工作,因为Unpack只接受TypeDicts--它不接受Union或dict[str,int]:
class FooKnownKwargs(TypedDict):
x: bool
FooKwargs = Union[FooKnownKwargs, dict[str, int]]
def foo(**kwargs: Unpack[FooKwargs]) -> None:
...
def f(a: str, b: str, **kwargs: Unpack[FooKwargs]) -> None:
print(a + b)
foo(**kwargs)
Again, what I'm looking for is:
再说一次,我要找的是:
- A type for
**kwargs
so that I don't need to explicitly specify an x
parameter in the signatures of foo
and f
.
- In
f()
, I don't want to explicitly pass x
to foo()
. I would like x
to go along with the **kwargs
automatically, but also keep the type.
更多回答
The entire point of using kwargs
in that way, without separating out x
specially, is to indicate that you do not care about tracking details at that level. That was true before annotations were added to the language, before annotations became widely used for third-party type-checking tools, and is still true now.
以这种方式使用kwargs而不特别分隔x的全部目的是为了表明您并不关心跟踪该级别的详细信息。在将注释添加到语言之前,在注释被广泛用于第三方类型检查工具之前,这是正确的,现在仍然是如此。
@KarlKnechtel that may have been true in the past, but the addition of Unpack
shows that it is not the case anymore. peps.python.org/pep-0692
@KarlKnechtel这在过去可能是真的,但Unpack的添加表明情况不再是这样了。Peps.python.org/pep-0692
I think that something like your "half-magic" attribute could be a viable addition to PEP692, consider bringing it up on its discussion topic ("Accepted" status is not "Final", new detail can be added). There was a sort of similar addition to dataclasses
in 3.10: KW_ONLY
constant that makes following attributes kw-only in constructor, so a precedent exists. It may also work as a metaclass argument (so that you do smth like class MyArgs(TypedDict, rest=int)
).
我认为像你这样的“半魔法”属性可能是PEP692的一个可行的补充,考虑在它的讨论主题中提出它(“接受”状态不是“最终”,可以添加新的细节)。在3.10中有一种类似的对数据类的添加:kw_only常量,它使以下属性仅在构造函数中具有kw,因此存在先例。它还可以用作元类参数(这样您就可以像类MyArgs(TyedDict,rest=int)一样工作)。
我是一名优秀的程序员,十分优秀!