字符串枚举

时间:2020-09-28 09:54:40

标签: python enums

在我的应用中,我正在像这样的JSON API中传递错误原因:{"ok": false, "reason": "EMAIL_ALREADY_REGISTERED"}。但是,使用这样的纯字符串很容易受到诸如仅键入"EMAIL_REGISTERED"或各种错字之类的错误的影响。

因此,我考虑过创建一些util以仅允许固定的一组值。我的第一个想法是枚举:

from enum import Enum
class ErrorReason(Enum):
    EXCEPTION = 1
    EMAIL_ALREADY_REGISTERED = 2
    PASSWORD_TOO_SHORT = 3

当我键入ErrorReason.E并检查给定值是否有效时,IDE(PyCharm)会自动为我建议可能的值,这很不错,但是,它也有缺点:

  • 有我不需要的不必要的数值
  • 在传递该值时对其进行序列化:str创建"ErrorReason.EXCEPTION",但我也可以执行ErrorReason.EXCEPTION.name.value(获取数值),然后{{ 1}}默认情况下不支持它,因此我需要设置一个JSON序列化器子类
  • 在我看来,这不是对Enum的正确/预期用途

另一种实现方式可能是:

flask.jsonify

这看起来更干净一些,class ErrorReason: EXCEPTION = "EXCEPTION" EMAIL_ALREADY_REGISTERED = "EMAIL_ALREADY_REGISTERED" PASSWORD_TOO_SHORT = "PASSWORD_TOO_SHORT" 评估为简单的字符串,但也感觉不对–我必须将每个可能的值写两次,并且出于这个唯一目的的对象对我来说太过分了。

实现此目标的最佳方法是什么?或者至少,在上一个示例中创建“哑”简单对象而不输入两次所有内容,同时保留智能IDE建议的最佳方法是什么?


编辑1:我找到了一种生成给定类的方法。但是,即使我生成了注释,PyCharm仍然不会执行任何自动完成建议。

ErrorReason.EXCEPTION

有关如何动态创建类的信息,请参见this answer的开头。

2 个答案:

答案 0 :(得分:2)

您可以使用automatic enum values并更改auto()__str__的行为:

from enum import Enum, auto

class ErrorReason(str, Enum):

    def _generate_next_value_(name, start, count, last_values):
        return name

    def __str__(self):
        return self.name

    EXCEPTION = auto()
    EMAIL_ALREADY_REGISTERED = auto()
    PASSWORD_TOO_SHORT = auto()

现在:print(ErrorReason.EMAIL_ALREADY_REGISTERED)将只是EMAIL_ALREADY_REGISTERED

如汤姆·沃西克(Tom Wojcik)的回答所述,它也继承自str,以使其可由json序列化。

答案 1 :(得分:2)

有我不需要的不必要的数值

您需要它们。从字面上看,这就是您的回报。我知道您只需要namevalue中的一个是什么意思,但最好保持不变。 auto对此有所帮助。

在传递该值时将其序列化:str创建“ ErrorReason.EXCEPTION”,但我也可以执行ErrorReason.EXCEPTION.name或.value(获取数值),而flask.jsonify不支持默认,所以我需要设置一个JSON序列化器子类

实际上,Enum不可序列化。

默认情况下会失败

from enum import Enum
import json


class ErrorReason(Enum):
    EXCEPTION = "EXCEPTION"
    EMAIL_ALREADY_REGISTERED = "EMAIL_ALREADY_REGISTERED"
    PASSWORD_TOO_SHORT = "PASSWORD_TOO_SHORT"


print(json.dumps({"exc": ErrorReason.EXCEPTION}))

使用

TypeError: Object of type ErrorReason is not JSON serializable

这就是为什么鼓励将其与str(请看父母)一起使用的原因。

from enum import Enum
import json


class ErrorReason(str, Enum):
    EXCEPTION = "EXCEPTION"
    EMAIL_ALREADY_REGISTERED = "EMAIL_ALREADY_REGISTERED"
    PASSWORD_TOO_SHORT = "PASSWORD_TOO_SHORT"


print(json.dumps({"exc": ErrorReason.EXCEPTION}))

使用str mixin可以很好地进行序列化。