I am trying to do the following (simplified example) in a high efficiency function (trying to avoid copy), without using NotRequired
(for reasons shown after):
Mytd1 = TypedDict("Mytd1", {a: NotRequired[str], x: int})
Mytd_extra = TypedDict("Mytd_extra", {a: str, x: int, z: str})
def foo(y: Mytd1) -> Mytd_extra:
# users input object should NOT contain z
y = cast(Mytd_extra, y). # fails - my guess is `a` is the offender
y["z"] = "hooray"
if "a" not in y:
y["a"] = "whatever"
return y
Mypy complains about the cast as "incompatible types in assignment", but it's what I want to do. How do I achieve this? I think a
is the offender - it's required on the output type
I do not want:
# kill Mytd1
Mytd_extra = TypedDict("Mytd_extra", {x: int, z: NotRequired[str]})
because this would allow the client to pass in {x: 5, z: "asdf"}
into foo
but that should be forbidden - they are only allowed to pass {x: 5}
.
I think the following would be doable but I'm trying to avoid it for efficiency as this function is called many times:
def foo(y: Mytd1) -> Mytd_extra:
new_var: Mytd_extra = {k: v for k:v in y.items()}
new_var["z"] = "ohno"
return new_var
CodePudding user response:
You have at least two completely valid solutions (assuming python 3.11 not to bother with typing
vs typing_extensions
, adjust your imports if needed). The problem is that y
is of type Mytd1
, so you cannot assign Mytd_extra
(result of cast) to it.
Use another variable
from typing import TypedDict, NotRequired, cast
Mytd1 = TypedDict("Mytd1", {'a': NotRequired[str], 'x': int})
Mytd_extra = TypedDict("Mytd_extra", {'a': str, 'x': int, 'z': str})
def foo(orig_y: Mytd1) -> Mytd_extra:
# users input object should NOT contain z
y = cast(Mytd_extra, orig_y)
y["z"] = "hooray"
if "a" not in y:
y["a"] = "whatever"
return y
Here is a playground with this solution.
Allow redefinition (mypy flag)
Preserve your original code, but run with --allow-redefinition
(or add allow_redefinition = true
to config file you use): playground.
Warning: allow_redefinition
does not have Super Cow Powers, it's use case is limited to a single scenario: assignment to a pre-defined variable, when expression in RHS includes this variable. It allows the following:
y = 'abc'
y = list(y)
but not this:
y = 'abc'
y = 1