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
TypedDict
andUnpack
. This allows only predetermined argument names, and each can have a different type. - The normal way, like
**kwargs: T
, whereT
is 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
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 likeclass MyArgs(TypedDict, rest=int)
).