有没有办法在 Python TypedDict 中指定任意额外内容?

问题描述 投票:0回答:3

我想指定一个

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

我尝试过的事情:

  • 阅读文档、Python 官方和 mypy - 没有找到有用的示例
  • 用继承
    TypedDict
    和常规字典的类对我的
    TypedDict
    类进行子类化 - 没有“编译”,也没有给我一种传递“其余”的方法
python mypy typing pylance pyright
3个回答
3
投票

使用 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" 

但这不允许任意字段。


1
投票

如果我理解正确的话,你需要一个 kwargs 类型,它指定 kwargs must 包含一些具有特定类型的“东西”,但也可以包含其他东西。我能想到的最简单的方法是实际上避免

TypedDict
,而是直接指定已知类型:

def wrapper(*args: Any, thing_id: str, **kwargs: Any) -> R

0
投票

Python TypedDict 尚不支持额外项目,可能会在 python3.13 中支持。参见PEP728

© www.soinside.com 2019 - 2024. All rights reserved.