从通用注释添加类属性

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

我需要从函数添加属性,但找不到类型提示支持它的方法。

尝试使用协议联合表示返回类型时会出现问题。

from typing import Any, Protocol, TypeVar, Union


class JsonDictBase(Protocol): ...
class JsonDict(JsonDictBase, Protocol):
    def __init__(self, **kwargs: Any) -> None: ...
    key: str
    value: int
    other: Any


T = TypeVar('T', bound=JsonDictBase)


def build(cls: Union[T, type[JsonDictBase]]) -> Union[T, type[JsonDict]]:
    ...


@build
class MyClass:
    name: str

cls = MyClass  # type[MyClass] | type[JsonDict]

instance = MyClass(key='as')  # fails

我期望

build
函数做的是将 JsonDict 协议属性添加到输入的类中。不使用继承

@build
class MyClass:
    name: str


# So python understands this
class MyClass:
    name: str
    def __init__(self, **kwargs: Any) -> None: ...
    key: str
    value: int
    other: Any

python type-hinting python-typing
1个回答
0
投票

您在这里要做的是使用

build
创建
MyClass
JsonDict
的交集类型。交集类型与并集类型相反。
Union[A, B]
表示为
A
B
的类型。
Intersection[A, B]
表示
A
B
的类型。遗憾的是 python 还不支持交集类型 - 不过它已经在工作了

Pyright 内部确实支持交叉类型 - 有一个解决方法,但遗憾的是仅使用该装饰器是不可能的。其他类型检查器也可能支持该模式,但我不知道这些。


from typing import TYPE_CHECKING, Any, Protocol, TypeVar

class JsonDictBase(Protocol): ...
class JsonDict(JsonDictBase, Protocol):
    def __init__(self, **kwargs: Any) -> None: ...
    key: str
    value: int
    other: Any

T = TypeVar('T', bound=type[JsonDictBase])

def build(cls: T) -> T: # note 'build' doesn't do anything regarding typing
    ...

@build
class MyClass:
    name: str

if TYPE_CHECKING: 
    # afaik there's no way to avoid this assert if you want an intersection
    assert issubclass(MyClass, JsonDict)


cls = MyClass  # type[<subclass of MyClass and JsonDict>]

instance = MyClass(key='as')  # succeeds
instance.name
instance.value

注意:由于交叉类型不是一个合适的功能,它们有时表现得有点古怪。您可能会收到漏报和令人困惑的错误消息,因此请做好准备。

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