从数据类生成Python中的函数签名

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

我想要一个定义一堆常量的文件,这样我以后就不需要对它们进行硬编码。

例如,我会这样做:

@dataclass(frozen=True)
class CONSTANTS:
    STATUS_SUCCESS = 200
    STATUS_ERROR = 400

    SI_UNIT_MASS = "kg"
    SI_UNIT_LENGTH = "m"

现在假设我有以下功能:

def func():
    something = True
    if something:
        return CONSTANTS.STATUS_SUCCESS
    else:
        return CONSTANTS.STATUS_ERROR

我想要

func
的类型提示。 所以我想我可以添加这个:

@dataclass(frozen=True)
class TYPES:
    STATUS = Literal[CONSTANTS.STATUS_SUCCESS, CONSTANTS.STATUS_ERROR]
    SI_UNIT = Literal[CONSTANTS.SI_UNIT_MASS, CONSTANTS.SI_UNIT_LENGTH]

并更新函数签名:

def func() -> TYPES.STATUS:

但在这里我得到这个错误:

Variable not allowed in type expressionPylancereportInvalidTypeForm

当我写下错误就消失了:

@dataclass(frozen=True)
class TYPES:
    STATUS = Literal[200, 400]
    SI_UNIT = Literal["kg", "m"]

但这有一个缺点,我可能会忘记向类型添加新的单元或状态代码。我希望这是动态的,这样我就不必重复自己。

有标准方法可以做到这一点吗? 我还想以某种方式重写

CONSTANTS
,这是我想要的

@dataclass(frozen=True)
class CONSTANTS:
    STATUS = STATUS
    SI_UNIT = SI_UNIT

@dataclass(frozen=True)
class STATUS:
    SUCCESS = 200
    ERROR = 400

...

所以我的想法是,我也许应该让

OPTIONS
STATUS
继承自定义类似
TYPE
属性的基类。但我找不到一个感觉自然的例子。

python type-hinting
1个回答
0
投票

我可以向您展示为什么会出现错误,但这并不能解决您的问题。

首先,错误是什么?它说“类型表达式中不允许变量”。为什么这是有意义的,因为在 python 中没有任何东西是受保护的(或私有的),所有变量都可以改变。例如:

print(func())
# >>> 200

CONSTANTS.STATUS_SUCCESS = "SUCCES"

print(func())
# >>> SUCCES

对于

TYPES.STATUS
变量也会发生同样的情况,当用户将其设置为
TYPES.STATUS = None
时会发生什么?

您可以划分类别并在更有意义的地方使用

ENUM
。或者您可以查看
@overload
装饰器,它可用于定义不同的返回类型,具体取决于输入类型。

这是使用枚举的解决方案:

from enum import IntEnum, StrEnum


class STATUS(IntEnum):
    SUCCESS = 200
    ERROR = 400


class UNIT(StrEnum):
    SI_UNIT_MASS = "kg"
    SI_UNIT_LENGTH = "m"


def func() -> STATUS:
    something = True
    if something:
        return STATUS.SUCCESS
    else:
        return STATUS.ERROR


print(func())
# >>> 200

根据 python 文档: 枚举是一组绑定到唯一值的符号名称。它们与全局变量类似,但它们提供了更有用的 repr()、分组、类型安全和一些其他功能。

用我的话来说,我想说数据类更适合作为存储数据的方法,例如拥有多个用户的 User 类。枚举类包含预定义的数据(在本例中为 SUCCES 和 ERROR)。这就是我建议切换到 ENUM 的原因。

返回值现在是一个 ENUM,但如果您在字符串中使用它,它将打印该值。因此

print(func()) -> 200
但是
print(func().__repr__()) -> <STATUS.SUCCESS: 200>

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