【问题标题】:Type annotations for Enum attribute枚举属性的类型注释
【发布时间】:2019-03-08 13:09:21
【问题描述】:

我有这段代码:

import enum


class Color(enum.Enum):
    RED = '1'
    BLUE = '2'
    GREEN = '3'


def get_color_return_something(some_color):
    pass

如果我想我会从 Color 枚举中接收一个枚举属性(例如:Color.RED),我该如何正确地在这个函数中为 some_color 变量添加类型注释?

【问题讨论】:

  • Color.RED.value ?
  • 是的,some_color 应该具有来自颜色枚举 @GraphicalDot 的值
  • 我建议进行编辑,因为问题实际上是关于枚举属性,而不是值。

标签: python python-3.x type-hinting typing python-typing


【解决方案1】:

类型提示 Color 类应该可以工作:

def get_color_return_something(some_color: Color):
    print(some_color.value)

【讨论】:

  • 如果我将 Color.RED 传递给此函数,我会收到警告“预期类型 'Color',而得到 'str'”。
  • 我无法重现此警告。在我的 Python 控制台中,我得到>>> get_color_return_something(Color.RED) 1。到目前为止没有任何警告。
  • @Gazzini 这个插件可能有助于警告。 pypi.org/project/pylint-enums
  • 如果您使用此语法进行类型提示,为了代码的清晰/可读性,最好将这些枚举类放在名为“types”或类似名称的单独模块/文件夹中。
  • @Gazzini 我在本地看不到,这个在线 mypy 检查器也没有显示:link
【解决方案2】:
def get_color_return_something(some_color: Color):
    pass

【讨论】:

    【解决方案3】:

    您可以尝试使用带有类型提示文字的选项。

    official PEP8 documentation 我们知道:

    Literal 它是一种类型,可用于向类型检查器指示相应的变量或函数参数具有与提供的文字(或多个文字之一)等效的值

    因此,如果您需要为函数参数使用某些特定值,它将是最佳选择之一。但是由于 Enum 值的类型,这种方法不会像我们预期的那样完全有效。每个值都将具有 Enum 类的类型。这意味着对于下面的代码示例,我们将能够将 Color.GREEN 作为函数参数。所以这样的解决方案对于开发人员来说只是信息,而不是函数参数的强制性规则。

    class Color(enum.Enum):
        RED = '1'
        BLUE = '2'
        GREEN = '3'
    
    print(type(Color.RED)  # will return <enum 'Color'>
    
    

    代码示例:

    from enum import Enum
    from typing import Literal
    
    
    class Color(Enum):
        RED = '1'
        BLUE = '2'
        GREEN = '3'
    
    def some_function(some_color: Literal[Color.RED, Color.BLUE]) -> None:
        pass
    

    第二个选项是@ibarrond 从post above 提供的完全正确的解决方案,只有一个类类型提示。

    some_color: Color
    

    因此,您可以在此处根据需要选择要使用的选项。

    在我看来,我们可以尝试为开发人员指定可能的 Enum 值,以便更清楚地了解我们对函数的要求。

    【讨论】:

      【解决方案4】:

      另一个奇怪的语法变通方法是使用前向引用语法(根据PEP 484)将 Enum 成员指定为 Enum 类的类型:

      from enum import Enum
      
      
      class ETest(Enum):
          EXAMPLE: 'ETest' = "example"  <--- forward referenced type
      
      
      def example() -> ETest:
          return ETest.EXAMPLE
      
      
      print(type(ETest.EXAMPLE.value))
      
      <class 'str'>
      

      在下图中,很明显 PyCharm 中突出显示的警告不再存在。

      作为参考,这里是 PyCharm 申诉的屏幕截图,其中将 EXAMPLE 成员指定为 &lt;str&gt; 类型是有意义的:

      我不是这种方法的粉丝,但它确实消除了警告。

      【讨论】:

      • 我一直在寻找这样的文档,太奇怪了。这是一种较新的行为吗?我不记得这是 Enum 在 Python 3.5 中出现的问题。
      • TBH 我不知道。我最近才开始使用 Python Enums,但无法确定问题何时出现。
      【解决方案5】:

      以下内容适用于 Pyton 3.9/PyCharm

      from enum import Enum
      from typing import Optional, Union
      
      
      class Color(Enum):
          RED: int = 1
          GREEN: int = 2
      
      
      def guess_color(x: Union[Color.RED, Color.GREEN]) -> Optional[ValueError]:
          if x == Color.RED:
              print("Gotcha!")
          else:
              return ValueError(f"It's not {Color.RED}")
      
      
      guess_color(Color.RED)
      

      【讨论】:

      • 为什么要返回 ValueError 而不是提高它?此外,此功能将无法通过 mypy 检查。看到这个gist on mypy playground
      • @Georgy:我并没有真正考虑返回ValueError,但这与我想要展示的内容无关。如果您愿意,请用打印语句替换该行。另外,我没有使用 mypy 的经验,所以我无法帮助您,抱歉。我明确声明它适用于 Python 3.0/PyCharm,除此之外我没有任何要求。
      • 您可以在输入时使用Literal[Color.RED] 来使其正常工作。我试图建议编辑,但看起来队列已满。 (您还需要在 if 条件下返回 None
      • 这个答案对我有帮助,因为它表明我可以键入类似于dataclass 的类属性。
      • 这真的违背了枚举的目的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-29
      • 1970-01-01
      • 2020-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多