我想指定一个
TypedDict
来指定一些字段和类型,但也允许拥有一个“包”,其中包含字典中允许的额外内容。
一个具体的例子是将输入信息添加到与 Flask 结合使用的装饰器中(因为,如果我没记错的话,flask
route
装饰器将“路径参数”作为关键字参数传递。我希望能够访问 kwarg
、操作它并传递它。
我的装饰器可能看起来或多或少像这样:
from typing import Any, Callable, ParamSpec, Tuple, TypedDict, TypeVar
from myproject.models import Thing
P0 = ParamSpec("P0")
P1 = ParamSpec("P1")
R = TypeVar("R")
# I know these TypedDicts aren't valid, but hopefully they illustrate what I want.
class IncomingKwargs(TypedDict):
thing_id: str
**rest
class ForwardedKwargs(TypedDict):
thing: Thing
**rest
Decoratee = Callable[P0, R]
Decorated = Callable[P1, R]
# Take the following with a grain of salt...
def with_thing() -> Callable[[Decoratee], Decorated]:
def decorator(f: Decoratee) -> Decorated:
def wrapper(*args: Any, **kwargs: IncomingKwargs) -> R
# Example manipulation.
thing = Thing.from_id(kwargs["thing_id"])
return f(*args, thing=thing, **kwargs["rest"])
return wrapper
return decorator
# And then later, something Flasky like:
@app.route("/things/:thing_id/frobnicate", method=["POST"])
@with_thing()
def frobnicate_thing(thing: Thing) -> Tuple[str, int]:
# Do stuff with the thing...
return "Thing was frobnicated.", 200
我看过https://docs.python.org/3/library/typing.html#typing.TypedDict,像
total=False
这样的选项似乎不是我想要的,因为我想要thing_id
需要钥匙。
FWIW,我可能可以像这样在 TypeScript 中实现我想要的打字:
type IncomingKwargs = {
thing_id: str,
[key: str]: any,
}
const someKwargs: IncomingKwargs = {thing_id: "12345", description: "A beautiful thing",}
// Now `thing_id` is a string and `rest` is an object/dict of the other things.
const { thing_id, ...rest } = someKwargs
我尝试过的事情:
TypedDict
和常规字典的类对我的 TypedDict
类进行子类化 - 没有“编译”,也没有给我一种传递“其余”的方法使用 TypeDict 可以做的事情是将
total
而不是 total
字段与继承混合在一起:
class Movie(TypedDict, total=True):
name: str
class Movie2(Movie, total=False):
year: int # optional
rating: int # optional
x: Movie2
x = {'name': 'a'} # mypy ok
x = {'name': 'a', 'year': 3} # mypy ok
x = {'name': 'a', 'year': 3, 'rating': 6} # mypy ok
x = {'year': 3, 'rating': 6} # mypy error: Missing key "name"
但这不允许任意字段。
如果我理解正确的话,你需要一个 kwargs 类型,它指定 kwargs must 包含一些具有特定类型的“东西”,但也可以包含其他东西。我能想到的最简单的方法是实际上避免
TypedDict
,而是直接指定已知类型:
def wrapper(*args: Any, thing_id: str, **kwargs: Any) -> R
Python TypedDict 尚不支持额外项目,可能会在 python3.13 中支持。参见PEP728