I was wondering whether following was possible with TypedDict
and Unpack
, inspired by PEP 692...
Regular way of using TypedDict
would be:
class Config(TypedDict):
a: str
b: int
def inference(name, **config: Unpack[Config]):
c = config['a']+str(config["b"])
config: Config = {"a": "1", "b": 2}
inference("example", **config) # or I could get argument hinting for each one from Config
However, I would be really interested if I could somehow unpack those keys to make it behave like they were directly introduced as variables into function signature:
def inference(name, **?: Unpack[Config]):
c = a+str(b)
so to mimic this explicit approach:
def inference(name, a: str, b: int):
c = a + str(b)
My motivation is I want to still leave code uncluttered with field or key access (verbose_name.another_verbose_name
or verbose_name["another_verbose_name"]
, where latter has no type hinting in VSC). Also, this way I could define TypedDict
for Config
once, and when needing some new parameter for my inference
, i could just straight add it to Config
definition, without changing inference
signature.
Currently my workaround is explicit definition of arguments in inference
signature and still invoking this with inference(name, **config)
. I still prefer this approach more than Dataclass, since I can skip asdict(dataclass_config) doing it so, which feels very unnecessary, especially when loading config from yaml or similar...
Maybe my approach is all wrong and not suiting to the best practices... Also would love your input on this. Im just starting using more advanced Python topics...
I can imagine that adding this functionality via PEP would require more than just typing work, so I would like to know if there is some common established solution.
No, there is no python syntax that will allow you to "unpack the dictionary to make it behave like they were directly introduced as variables into function signature".
You could technically do it at runtime with something like this:
def inference(name, **config: Unpack[Config]):
vars().update(config)
dosomething(a, b)
but that's very hacky, and the typechecker would not recognize subsequent uses of a
or b
(even though they will work at runtime).
The typechecker will only recognize a variable if it is declared or passed as argument.
I understand you want to declutter your code, but as @Barmar's comment suggests, skipping variable declarations may not be the best way to do that if you are actually using those variables in your function. **
and Unpack
are mostly useful if those arguments are passed down to another function