跨不同 Python 模块访问列表时的行为不一致

Inconsistent Behavior of a List When Accessed Across Different Python Modules

提问人:Luc Hayward 提问时间:11/10/2023 更新时间:11/10/2023 访问量:35

问:

我在 Python 中遇到了一个特殊的问题,该列表在跨不同模块访问时似乎表现不一致。我有三个 Python 文件:main.py、mymodule.py 和 myothermodule.py。列表 main.py 中定义,mymodule.py 中修改。但是,当我从不同的模块打印时,它显示不同的内容。从内部 main.py 变量的副本与我在其他模块中使用时访问它时不同。mylistmylistmylistmain.mylist

下面是一个最小的工作示例:main.py

import mymodule
import myothermodule

mylist = []

def run():
    print("In main func")
    mymodule.bar()
    print(f"In run {mylist=}")

if __name__ == '__main__':
    print("In main guard")
    run()
    print(f"In main guard again {mylist=}")
    myothermodule.foo()

mymodule.py

import main

def bar():
    print("In bar() appending to main.mylist")
    main.mylist.append(1)
    print(f"{main.mylist=}")

myothermodule.py

import main

def foo():
    print(f"In myothermodule.foo() {main.mylist=}")

当我运行 main.py 时,我得到以下输出:

In main guard
In main func
In bar() appending to main.mylist
main.mylist=[1]
In run mylist=[]
In main guard again mylist=[]
In myothermodule.foo() main.mylist=[1]

预期输出为:

In main guard
In main func
In bar() appending to main.mylist
main.mylist=[1]
In run mylist=[1]
In main guard again mylist=[1]
In myothermodule.foo() main.mylist=[1]

如您所见,在 main.py 中访问时未更新mylist

列表 python-import python-module

评论

2赞 Abdul Aziz Barkat 11/10/2023
这回答了你的问题吗?使用相互导入或循环(循环)导入时会发生什么情况?具体看这个答案:stackoverflow.com/questions/744373/......
0赞 Luc Hayward 11/10/2023
谢谢@AbdulAzizBarkat,这并不能完全解决我的问题。当我们到达主守卫并开始调用我们的函数时,所有模块都已完全导入?即使将 mylist 的定义移到 main.py 的顶部也不能解决这个问题吗?
0赞 Abdul Aziz Barkat 11/10/2023
这真的是你的问题,循环导入(以及它是循环导入的事实)。您正在运行,因此它最初加载为 when 并导入它,它被加载为再次执行。解决您的循环导入问题,这应该会自行解决。例如,如果在定义之前添加打印,则会看到打印执行了两次__main__main.py__main__mymodulemyothermodulemainmylist
0赞 Luc Hayward 11/10/2023
所以你是说没有办法定义一个可以从 和 访问的变量?我必须定义它并改用它吗?main.pymain.pymymodule.pyanothermodule.py
1赞 Abdul Aziz Barkat 11/10/2023
是的,只要你想导入并成为你正在运行的模块()。您可以移动到第四个模块,也可以实际创建第四个模块。mainmymoduleanothermodule__main__mylist__main__

答:

0赞 Impulsleistung 11/10/2023 #1

您遇到的问题是在 Python 中处理全局变量和导入时的常见问题。由于 Python 处理模块导入的方式和全局变量的定义,出现了这个问题。

在您的设置中,导入 和 ,这两个模块都导入 .此循环导入在 和 中创建模块的单独实例。因此,in 和 与 .main.pymymodule.pymyothermodule.pymain.pymainmymodulemyothermodulemylistmymodulemyothermodulemylistmain.py

当追加到 时,它会在自己的实例中修改 ,而不是原始脚本中的实例。同样,正在访问其自己的实例。mymodule.bar()main.mylistmylistmainmain.pymyothermodule.foo()mylistmain

若要解决此问题,可以重构代码以避免循环导入,并以不同的方式使用共享状态。一种常见的方法是将参数传递给其他模块中的函数,而不是导入到这些模块中。以下是修改代码的方法:mylistmain.py

main.py:

import mymodule
import myothermodule

mylist = []

def run():
    print("In main func")
    mymodule.bar(mylist)
    print(f"In run {mylist=}")

if __name__ == '__main__':
    print("In main guard")
    run()
    print(f"In main guard again {mylist=}")
    myothermodule.foo(mylist)

mymodule.py:

def bar(mylist):
    print("In bar() appending to mylist")
    mylist.append(1)
    print(f"{mylist=}")

myothermodule.py:

def foo(mylist):
    print(f"In myothermodule.foo() {mylist=}")

通过这些更改,将显式传递给其他模块中的函数,从而确保对同一列表实例进行所有修改。这种方法避免了循环导入,并确保了不同模块之间状态的一致性。mylistmylist

评论

0赞 Luc Hayward 11/10/2023
mymodule.bar() 和 myothermodule.foo() 都访问相同的 main 实例,而不是您所说的它们自己的实例。我知道我可以通过它,但我正在寻找的是了解为什么这不起作用。