代码之家  ›  专栏  ›  技术社区  ›  Q42

如何让Pyright从枚举检查中推断类型?

  •  0
  • Q42  · 技术社区  · 6 月前

    类型是否可以与枚举相关联,以便Pyright可以从等式检查中推断出类型?(没有 cast() isinstance() .)

    from dataclasses import dataclass
    from enum import Enum, auto
    
    class Type(Enum):
        FOO = auto()
        BAR = auto()
    
    @dataclass
    class Foo:
        type: Type
    
    @dataclass
    class Bar:
        type: Type
    
    item = next(i for i in (Foo(Type.FOO), Bar(Type.BAR)) if i.type == Type.BAR)
    reveal_type(item)  # How to have this be `Bar` instead of `Foo | Bar`?
    
    1 回复  |  直到 6 月前
        1
  •  0
  •   InSync Christian C. Salvadó    6 月前

    你想要一个 受歧视的工会 (也称为 tagged union ).

    在受歧视的工会中,存在 鉴别器 (也称为a 标签字段 )其可用于区分成员。

    您当前有一个联盟 Foo Bar ,你想用 .type 属性。但是,此字段不能作为鉴别器,因为它对联盟的每个成员都没有不同。

    (游乐场: Pyright , Mypy )

    for i in (Foo(Type.FOO), Bar(Type.BAR)):
        reveal_type(i)  # Foo | Bar
    
    mischievous_foo = Foo(Type.BAR)  # This is valid
    naughty_bar = Bar(Type.FOO)      # This too
    
    for i in (mischievous_foo, naughty_bar):
        if i.type == Type.FOO:
            reveal_type(i)           # Runtime: Bar, not Foo
    

    如果 Foo.type 只能是 Type.FOO Bar.Type Type.BAR ,那么在类型中反映这一点很重要:

    (制作 type 此时,数据类字段不再有意义,但我假设就这个问题而言,它们只是数据类。)

    @dataclass
    class Foo:
        type: Literal[Type.FOO]
    
    @dataclass
    class Bar:
        type: Literal[Type.BAR]
    

    As Literal[Type.FOO] Literal[Type.BAR] 是不相交类型, i 然后通过检查类型来缩小范围 .type :

    (游乐场: Pyright , Mypy )

    for i in (Foo(Type.FOO), Bar(Type.BAR)):
        if i.type == Type.FOO:
            reveal_type(i)           # Foo
    
    Foo(Type.BAR)  # error
    Bar(Type.FOO)  # error
    

    …即使在发电机中,是的:

    item = next(i for i in (Foo(Type.FOO), Bar(Type.BAR)) if i.type == Type.BAR)
    reveal_type(item)                # Bar