跨模块的Python枚举

18

如果在Python 3中,枚举类型在主模块中被定义,跨模块边界检查枚举相等性就无法正常工作。以下是一个例子:

moduleA.py:

#!/usr/bin/python3

import moduleB
from enum import Enum, unique

@unique
class MyEnum(Enum):
    A = 1
    B = 2
    # def __eq__(self,other):
    #     assert isinstance(other,self.__class__)
    #     return self.value == other.value

if __name__ == "__main__":

    myVar = MyEnum.B
    moduleB.doStuff(myVar)

moduleB.py:

#!/usr/bin/python3

import moduleA

def doStuff(aVariable):
    bVariable = moduleA.MyEnum.B
    assert aVariable == bVariable

在命令行上调用"./moduleA.py"会产生以下结果:

Traceback (most recent call last):
  File "./moduleA.py", line 17, in <module>
    moduleB.doStuff(myVar)
  File "/home/ruedi/Dropbox/Reps/stuffed/sosy/testing/moduleB.py", line 7, in doStuff
    assert aVariable == bVariable
AssertionError

在枚举中取消自定义等号运算符的注释会导致断言失败。我发现在这两种情况下类模块不同,因为其中一个是 "__main__"。

除了将枚举移动到其自己的模块之外,最“Pythonic方式”来解决这个问题是什么?

编辑: 切换到"aVariable is bVariable"也不起作用:

Traceback (most recent call last):
  File "./moduleA.py", line 17, in <module>
    moduleB.doStuff(myVar)
  File "/home/ruedi/Dropbox/Reps/stuffed/sosy/testing/moduleB.py", line 7, in doStuff
    assert aVariable is bVariable
AssertionError
1个回答

23

就Python而言,这里有三个模块:

  • __main__
  • moduleA
  • moduleB

您从命令行运行的文件,即主入口点,始终存储为__main__模块。如果您在代码的任何地方导入moduleA,Python将其视为与__main__模块分开,并创建一个新的模块对象。因此,您有两个独立的MyEnum类:

  • __main__.MyEnum
  • moduleA.MyEnum

它们的成员是不同的,因此不能相等。

如果您使用import __main__ as moduleA或使用单独的脚本文件来驱动测试,则测试会通过;那个单独的文件将成为__main__

#!/usr/bin/python3
# test.py, separate from moduleA.py and moduleB.py

import moduleA    
import moduleB

if __name__ == "__main__":
    myVar = moduleA.MyEnum.B
    moduleB.doStuff(myVar)

另一个解决办法是告诉Python,__main__moduleA是同一件事情;在导入moduleA(或导入moduleAmoduleB)之前,您可以向sys.modules添加另一个条目:

if __name__ == '__main__':
    import sys
    sys.modules['moduleA'] = sys.modules['__main__']

import moduleB

我认为这不太符合 Python 的风格。


1
有没有很好的理由解释为什么它会这样工作,为什么要区分__main__moduleA?难道你不认为它们应该是一样的吗? - TankorSmash
1
@TankorSmash:它们是分开的,因为你需要一种区分脚本的主入口和导入的模块的方法。这就是为什么 if __name__ == '__main__': 起作用的原因。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接