I’m trying to use Unpack, but I’m finding it too limited for my use case. I asked about it on StackOverflow and it was suggested that I bring it up here, because PEP 692 isn’t yet final.
There are two ways to specify types for **kwargs:
- The new way, with
TypedDictandUnpack. This allows only predetermined argument names, and each can have a different type. - The normal way, like
**kwargs: T, whereTis some type. This allows any argument names, and they all have to be of typeT.
The issue is that there are many practical use cases where you might want to do both. You might want to specify some arguments types with TypedDict, but also allow any other argument names, and for those arguments, they should all be of some type T.
For example, suppose I have this function:
def foo(*, x: bool, **kwargs: int) -> None:
...
And suppose it is called from many other functions, like this:
def f(a: str, b: str, x: bool, **kwargs: int) -> None:
print(a + b)
foo(x=x, **kwargs)
I would like it if I did not have to put x in f’s function signature, and also not explicitly pass x to foo().
I wish I could do something like this with TypedDict and Unpack, where _other_ represents any other argument names that are passed in:
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)
It’s worth mentioning that, in a response to my SO question, @sterliakov suggested some other possible paths:
There was a sort of similar addition to
dataclassesin 3.10:KW_ONLYconstant 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 likeclass MyArgs(TypedDict, rest=int)).