问一个 Python 枚举类的问题

2023-04-27 16:20:55 +08:00
 Ricardoo

今天偶然看到枚举的一种写法,我测试后感觉有些奇怪

import enum
class TestEnum( str,enum.Enum):
    A = "a"

这里同时继承了 str 和 Enum , 我测试了一下语句,

repr(TestEnum.A)
>>> "<TestEnum.A: 'a'>"

str(TestEnum.A)
>>> TestEnum.A'

TestEnum.A == 'a'
>>> True

这里的 TestEnum.A == 'a' 结果为 True , 是怎么判断的?

如果 TestEnum 是 dataclass 类的变量,在 json dumps 时也会自动转换,这是怎么做到的?

from dataclasses import dataclass, asdict
import json

@dataclass
class A:
    a: TestEnum=None
test_a = A(TestEnum.A)

asdict(test_a)

>>> {'a': <TestEnum.A: 'a'>}

json.dumps(asdict(test_a))
>>> {"a": "a"}

python 版本 3.9.16

1629 次点击
所在节点    Python
14 条回复
cosmain
2023-04-27 16:39:07 +08:00
多继承,继承了 str 的一些成员函数 == 应该是调用了成员方法。

不过这个还真是一个不错的方法。==也好,json 也好
westoy
2023-04-27 16:39:45 +08:00
因为 Enum 的实现里,Enum 的 members 本身就是这个 Enum 类的实例.......

而你 TestEnum 这个又是继承的 str

导致 TestEnum.A 也变成了 str......
arischow
2023-04-27 16:51:27 +08:00
zyx199199
2023-04-27 16:54:34 +08:00
Python 3.10 标准库里自带的 IntEnum 就是同时继承了 int 和 enum 实现的
Ricardoo
2023-04-27 16:56:11 +08:00
@westoy 我好像突然有点明白了,又不完全明白。为什么 str(TestEnum.A) 不是'a' ?, 为什么不是优先调用 str 类的__str__方法呢?
NoOneNoBody
2023-04-27 16:59:09 +08:00
对于最后的问题,查看手册关于 json.JSONEncoder.default() 的说明
就是 json 是如何处理 object 类型的(dict 是 object 类型)
NoOneNoBody
2023-04-27 17:02:41 +08:00
@Ricardoo #5
你搞错了
不是 TestEnum.__str__() 而是 TestEnum.A.__str__()
XYxe
2023-04-27 17:10:15 +08:00
@Ricardoo #5 因为 Enum 有 metaclass EnumType, 在 EnumType 里面对几个函数有特殊处理
TestEnum.__dict__ 可以看到添加的几个的函数
westoy
2023-04-27 17:13:42 +08:00
@Ricardoo

>>> TestEnum.__mro__
(<enum 'TestEnum'>, <class 'str'>, <enum 'Enum'>, <class 'object'>)

从左到右, 没定义就找下一个, 你的 TestEnum 里没定义__str__

可以追加一个

TestEnum.__str__ = lambda _: str(random.random())

a = str(TestEnum.A)
b = str(TestEnum.A)

print(a, b, a == b)

再试一下结果看看
Ricardoo
2023-04-27 17:24:40 +08:00
@westoy 按照 (<enum 'TestEnum'>, <class 'str'>, <enum 'Enum'>, <class 'object'>) 的顺序。TestEnum 没有 str 定义,但是<class 'str'> 里有__str__ 定义啊,为什么 str(TestEnum.A) 的结果是 TestEnum.A 呢? 我看了下,这是<enum 'Enum'>里__str__的定义,
def __str__(self):
return "%s.%s" % (self.__class__.__name__, self._name_)
所以 str(TestEnum.A) , 为什么跳过<class 'str'>, 出的是<enum 'Enum'>里__str__结果呢
XYxe
2023-04-27 17:36:03 +08:00
因为在 enum.EnumType 里面,给 TestEnum 增加了 __str__ 方法,你可以在 TestEnum.__dict__ 里面看到这个方法
lambdaq
2023-04-27 17:57:17 +08:00
学习。。原来写了那么多的 xxxenum.yyy.value == 'yyy' 都白写了。。
Ricardoo
2023-04-27 20:37:38 +08:00
@lambdaq 我之前也是这样写的,所以看到这个写法后测试了一下,发现确实好用。
noparking188
2023-04-28 01:10:10 +08:00
@lambdaq #12 我也是,觉得这样调用麻烦然后直接不继承 Enum 类了,学到了,这就去改代码

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/935970

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX