为什么Python中的可变值枚举相同的对象?

Bil*_*lly 18 python enums identity python-3.x

在为Enum成员试验不同的值类型时,我发现当值是可变的时会有一些奇怪的行为.

如果我将一个值定义Enum为不同的列表,那么成员的行为仍然类似于Enum值是典型的不可变类型,如strint,即使我可以更改成员的值,以便两个Enum成员的值相同:

>>> class Color(enum.Enum):
        black = [1,2]
        blue = [1,2,3]  

>>> Color.blue is Color.black
False
>>> Color.black == Color.blue
False
>>> Color.black.value.append(3)
>>> Color.black
<Color.black: [1, 2, 3]>
>>> Color.blue
<Color.blue: [1, 2, 3]>
>>> Color.blue == Color.black
False
>>> Color.black.value == Color.blue.value
True
Run Code Online (Sandbox Code Playgroud)

但是,如果我将值定义为相同的列表,则每个成员的值似乎是同一个对象,因此一个成员的值的任何突变都会影响所有成员:

>>> class Color(enum.Enum):
        black = [1,2,3]
        blue = [1,2,3]

>>> Color.blue is Color.black
True
>>> Color.black == Color.blue
True
>>> Color.black.value.append(4)
>>> Color.black
<Color.black: [1, 2, 3, 4]>
>>> Color.blue
<Color.black: [1, 2, 3, 4]>
>>> Color.blue == Color.black
True
Run Code Online (Sandbox Code Playgroud)

为什么Enum这样做?这是预期的行为还是一个错误?

注意: 我不打算以这种方式实际使用Enums,我只是尝试使用Enum成员的非标准值

use*_*ica 10

来自文档:

给定两个具有相同值的成员A和B(并且A定义为第一个),B是A的别名.A和B的值的值按字母顺序查找将返回A.B的名字查找也将返回A:

>>> class Shape(Enum):
...     square = 2
...     diamond = 1
...     circle = 3
...     alias_for_square = 2
...
>>> Shape.square
<Shape.square: 2>
>>> Shape.alias_for_square
<Shape.square: 2>
>>> Shape(2)
<Shape.square: 2>
Run Code Online (Sandbox Code Playgroud)

即使值是可变的,这也是平等运作的.由于您为black和定义了相等的值,因此blue,black首先blue是for的别名black.

  • 在第二个例子中我应该明白`<Color.black:[1,2,3,4]>`作为`color.blue`的`repr` ...谢谢! (3认同)

Jim*_*ard 5

要补充@ user2357112的答案,请查看EnumMeta所有Enum类的元类; 它可以查看具有类型的每个类定义,并进行更改以更改它.

具体来说,它需要 通过简单的赋值在其__new__方法中重新分配具有相同值的成员:

    # If another member with the same value was already defined, the
    # new member becomes an alias to the existing one.
    for name, canonical_member in enum_class._member_map_.items():
        if canonical_member._value_ == enum_member._value_:
            enum_member = canonical_member
            break
Run Code Online (Sandbox Code Playgroud)

我没有选择检查文档,而是查看源代码.课程:始终检查文档,如果ExplanationNotFound被提出; 检查来源:-)