Python联合类型与对象

iecba09b  于 2023-05-02  发布在  Python
关注(0)|答案(1)|浏览(112)

我正在为int,str,bool等编写自己的类。上面有发电机我使用它来模糊基于类型注解的函数。除了union类型的|符号之外,这一切都很顺利。如果我输入类似这样的内容:

def test_handles_none_with_arged_types(
    x: Int[0, 10] | List[Int] | Str | Dict[NoneType, List[NoneType]]
):
    assert type(x) in [int, list, str, dict, list]
    if type(x) == int:
        assert x >= 0 and x <= 10
    if type(x) == list:
        assert all([el is None for el in x])
    if type(x) == dict:
        for k, v in x.items():
            assert k is None
            assert type(v) == list
            for el in v:
                assert el is None

Python给出了以下错误:

TypeError: unsupported operand type(s) for |: 'Int' and 'List'

这似乎是因为Int[0,10]的类型是pybt.typing.Int,而不是type。但是,使用typing.Union工作得很好。

def test_handles_none_with_arged_types(
    x: Union[Int[0, 10], List[Int], Str, Dict[NoneType, List[NoneType]]]
):
    ...

有办法解决这个问题吗?不幸的是,我想不出一种方法来推迟示例化Int或其他在__class_getitem__下索引的类型。
编辑:
下面是完整的类(用于List):

class List:
    def __init__(self, sub_type=_DEFAULT_SUB_TYPE, max_len=_DEFAULT_MAX_LEN):
        self.max_len: int = _DEFAULT_MAX_LEN
        self.sub_type = sub_type
        if max_len is not None:
            self.max_len = max_len

    def __str__(self):
        return "pybt.types.List"

    def __class_getitem__(cls, parameters):
        sub_type = None
        max_len = None
        if type(parameters) != tuple:
            parameters = (parameters,)

        if len(parameters) > 2:
            raise TypeError("Expected 2 arguments: List[sub_type, max_length]")
        if len(parameters):
            sub_type = parameters[0]
        if len(parameters) > 1:
            max_len = parameters[1]

        if max_len and max_len <= 0:
            raise TypeError(f"Max Length of {cls.max_len} is less than or equal to 0")

        return cls(sub_type, max_len)
nwlls2ji

nwlls2ji1#

您已经知道dunder方法和type,因此,如果这个答案对您来说是显而易见的,请原谅。
要使Int() | List()(或任何创建示例的东西,如List[])工作,必须有Int.__or__List.__ror__,或两者都有。
这适用于Int | List中的类,因为type本身实现了__or____ror__

>>> type.__or__
<slot wrapper '__or__' of 'type' objects>

因此,尝试将以下方法添加到您的类中:

from typing import Union

class List:
    ...
    def __or__(self, other):
        return Union[self, other]
    def __ror__(self, other):
        return Union[self, other]

它似乎可以很好地与其他类型,甚至它自己的类:

>>> List() | List
typing.Union[<__main__.List object at 0x0000024A7F7F93D0>, __main__.List]

相关问题