V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Ricardoo
V2EX  ›  Python

问一个 Python 枚举类的问题

  •  
  •   Ricardoo · 358 天前 · 1614 次点击
    这是一个创建于 358 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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

    14 条回复    2023-04-28 01:10:10 +08:00
    cosmain
        1
    cosmain  
       358 天前
    多继承,继承了 str 的一些成员函数 == 应该是调用了成员方法。

    不过这个还真是一个不错的方法。==也好,json 也好
    westoy
        2
    westoy  
       358 天前
    因为 Enum 的实现里,Enum 的 members 本身就是这个 Enum 类的实例.......

    而你 TestEnum 这个又是继承的 str

    导致 TestEnum.A 也变成了 str......
    zyx199199
        4
    zyx199199  
       358 天前
    Python 3.10 标准库里自带的 IntEnum 就是同时继承了 int 和 enum 实现的
    Ricardoo
        5
    Ricardoo  
    OP
       358 天前
    @westoy 我好像突然有点明白了,又不完全明白。为什么 str(TestEnum.A) 不是'a' ?, 为什么不是优先调用 str 类的__str__方法呢?
    NoOneNoBody
        6
    NoOneNoBody  
       358 天前
    对于最后的问题,查看手册关于 json.JSONEncoder.default() 的说明
    就是 json 是如何处理 object 类型的(dict 是 object 类型)
    NoOneNoBody
        7
    NoOneNoBody  
       358 天前
    @Ricardoo #5
    你搞错了
    不是 TestEnum.__str__() 而是 TestEnum.A.__str__()
    XYxe
        8
    XYxe  
       358 天前
    @Ricardoo #5 因为 Enum 有 metaclass EnumType, 在 EnumType 里面对几个函数有特殊处理
    TestEnum.__dict__ 可以看到添加的几个的函数
    westoy
        9
    westoy  
       358 天前   ❤️ 1
    @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
        10
    Ricardoo  
    OP
       358 天前
    @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
        11
    XYxe  
       358 天前   ❤️ 1
    因为在 enum.EnumType 里面,给 TestEnum 增加了 __str__ 方法,你可以在 TestEnum.__dict__ 里面看到这个方法
    lambdaq
        12
    lambdaq  
       358 天前
    学习。。原来写了那么多的 xxxenum.yyy.value == 'yyy' 都白写了。。
    Ricardoo
        13
    Ricardoo  
    OP
       358 天前
    @lambdaq 我之前也是这样写的,所以看到这个写法后测试了一下,发现确实好用。
    noparking188
        14
    noparking188  
       358 天前
    @lambdaq #12 我也是,觉得这样调用麻烦然后直接不继承 Enum 类了,学到了,这就去改代码
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2849 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 06:14 · PVG 14:14 · LAX 23:14 · JFK 02:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.