【问题标题】:Python type hints for custom module level constants自定义模块级常量的 Python 类型提示
【发布时间】:2020-03-19 07:35:00
【问题描述】:

我正在尝试向我的类添加类型提示,但我正在努力解决模块级常量的这个特殊问题。在下面的示例中,我用 BLUECAR、REDCAR、YELLOWCAR、WHITECAR 替换了我的常量 - 简单地假设我的整个程序围绕这 4 个常量发展,这就是我明确定义它们的原因。

from collections import namedtuple
from typing import List, Union, TypeVar

# I define CarTypeRef from id and name
CarTypeRef = namedtuple("CarType", "id name")


# I define possible car types by id and name
BLUECAR: CarTypeRef = CarTypeRef (1, 'Blue Car')
REDCAR: CarTypeRef = CarTypeRef (2, 'Red Car')
YELLOWCAR: CarTypeRef = CarTypeRef (3, 'Yellow Car')
WHITECAR: CarTypeRef = CarTypeRef (4, 'White Car')
"""Car type init with id-name"""

# 1. try: this does not work:
CarType = TypeVar("CarType", BLUECAR, REDCAR, YELLOWCAR, WHITECAR)
"""Type alias for possible car types"""

# 2. try: this (type alias) does also not work:
CarType = Union[BLUECAR, REDCAR, YELLOWCAR, WHITECAR]

# I later use the following list
# e.g. to loop through available car types
CARTYPES: List[CarType] = [
    BLUECAR,
    REDCAR,
    YELLOWCAR,
    WHITECAR]
"""Available car types"""

对于这两种类型定义,我在运行时都会得到以下输出:

> 1.try: TypeError: Union[arg, ...]: each arg must be a type. Got CarType(id=1, name='Blue Car').
> 2. try: TypeError: TypeVar(name, constraint, ...): constraints must be types. Got CarType(id=1, name='Blue Car').

我做错了什么?如何为这 4 个常量创建自定义类型检查?

注意:当然,我可以简单地使用字符串(例如:“bluecar”、“redcar”、..),但是由于这 4 个常量在我的代码中经常出现,所以我想更明确一点 -既是为了代码的易读性,也是为了静态类型测试。

【问题讨论】:

  • BLUECARREDCAR 等是,而不是类型。看看enum.Enum,因为这正是你(糟糕地)用这段代码重新实现的。

标签: python constants alias type-hinting typing


【解决方案1】:

感谢@Aran-Fey 为我指明了正确的方向。我还没有听说过python中的枚举。我能够显着减少我的代码,现在只有:

class CarType(Enum):
    """Available car types"""
    BLUECAR = 1
    REDCAR = 2
    YELLOWCAR = 3
    WHITECAR = 4

而且我什至可以在不指定 str 作为名称的情况下获得人类可读的文本,例如:

>>>> print(Car.REDCAR.name.lower().capitalize())
Redcar

.. 虽然有点复杂。

此外,我不能直接导入 BLUECAR、REDCAR、YELLOWCAR 或 WHITECAR,这意味着我总是必须引用具有完整 Enum 类的那些,例如

from .typedef import CarType
if car_type in [CarType.BLUECAR, CarType.REDCAR, CarType.WHITECAR]:
    paint_yellow(car)

.. 代码远多于:

from .typedef import BLUECAR, REDCAR, WHITECAR

if car_type in [BLUECAR, REDCAR, WHITECAR]:
    paint_yellow(car)

[更新]

虽然 Enum 方法很好,但我最终使用了更适合我的目的的简单字符串常量,例如:

BLUECAR: str = "Blue Car"
REDCAR: str = "Red Car"
YELLOWCAR: str = "Yellow Car"
WHITECAR: str = "White Car"

CARTYPES: List[str] = [BLUECAR, REDCAR, YELLOWCAR, WHITECAR]

.. 因为我能做到:

from .typedef import BLUECAR, REDCAR, YELLOWCAR, WHITECAR, CARTYPES

for car_type in CARTYPES:
    ...
..
if car_type in [BLUECAR, REDCAR]:
    ...

我知道这是特定于如何使用这些变量的,也许汽车类型的例子并不适合描述我的真实实现场景。

【讨论】:

    猜你喜欢
    • 2015-05-01
    • 1970-01-01
    • 2012-11-30
    • 2021-05-30
    • 2019-04-12
    • 2020-11-23
    • 2017-06-18
    • 2019-12-22
    • 2017-03-06
    相关资源
    最近更新 更多