代码之家  ›  专栏  ›  技术社区  ›  Thomas

为什么在尝试将枚举用作另一个文件中的字典键时出现keyError?

  •  2
  • Thomas  · 技术社区  · 6 年前

    我有两个文件, enum_test.py print_test_file.py . 我在中定义了一个枚举类 枚举测试 并使用该枚举类的成员作为键创建字典。当我试图在 打印测试文件.py 我有一个钥匙错误。

    这是密码 枚举测试 :

    from enum import Enum
    import print_test_file
    
    class MyEnum(Enum):
        A = 1
        B = 2
    
    def main():
        enumDict = dict()
        enumDict[MyEnum.A] = 'abcd'
        enumDict[MyEnum.B] = 'efgh'
    
        print(enumDict[MyEnum.A])
        print_test_file.print_test(enumDict)
    
    if __name__ == "__main__":
        main()
    

    这是密码 打印测试文件.py

    import enum_test
    
    def print_test(enumDict):
        print(enumDict[enum_test.MyEnum.A])
    

    我本来以为你会跑 enum_test 将产生以下输出:

    abcd
    abcd
    

    但是它只打印第一个 abcd 然后投掷 KeyError: <MyEnum.A: 1>

    我如何使用我在其中创建的词典 枚举测试 打印测试文件.py ?

    1 回复  |  直到 6 年前
        1
  •  1
  •   abarnert    6 年前

    这就是为什么你永远不应该 import 与脚本运行的模块相同。最后得到两个完全独立的模块对象, enum_test __main__ ,具有自己完全独立的全局命名空间,其中包含从同一代码构造的独立对象。

    __main__.main() 生成一个dict,并用它填充 __main__.MyEnum 钥匙。

    print_test_file.print_test 将该dict作为参数。但是它试图用 enum_test.MyEnum.A . 而且这个钥匙不在口述里,所以你得到一个 KeyError .


    你的模块 具有循环依赖项,这被此问题掩盖。我敢肯定,在这种情况下,如果没有其他错误的话,您实际上可以摆脱循环依赖关系,但是必须仔细考虑顶级模块代码的执行顺序,这仍然令人困惑,因此最好避免它们。


    一次解决这两个问题的简单方法是将共享代码移动到单独的共享模块中,脚本和测试模块都可以导入该模块。

    # enum_test.py
    from my_enum import MyEnum
    import print_test_file
    
    def main():
        enumDict = dict()
        enumDict[MyEnum.A] = 'abcd'
        enumDict[MyEnum.B] = 'efgh'
    
        print(enumDict[MyEnum.A])
        print_test_file.print_test(enumDict)
    
    if __name__ == "__main__":
        main()
    

    # print_test_file.py
    import my_enum
    
    def print_test(enumDict):
        print(enumDict[my_enum.MyEnum.A])
    

    # my_enum.py
    from enum import Enum
    
    class MyEnum(Enum):
        A = 1
        B = 2
    

    现在,没有导入脚本的模块,也没有导入脚本的模块。(在技术术语中,您只需要一个树,脚本在根目录下,而不是一个包含循环的图。)


    每隔几年,就有人建议更改python以消除这个问题,但实际上没有好的答案。它们可能会导致导入作为脚本运行的同一个模块出错,但这可能会破坏一些不常见但重要的用例(如 multiprocessing )或者他们可以通过做一个隐式的 sys.modules['enum_test'] = sys.modules['__main__'] 在某些情况下,实际上没有什么地方可以将代码中的循环依赖性(以及几乎所有其他关于这个问题的例子)从最无害的转为严重的bug。

    (顺便说一句,我隐约记得,在一次讨论中,一位核心开发人员,也是一位老师,提到他的学生中很少有人会遇到这个问题,但是那些确实会接近班上最高水平的学生,所以至少你要有这种感觉。)