【问题标题】:Weird output of method for circular import in PythonPython中循环导入方法的奇怪输出
【发布时间】:2013-01-07 01:12:14
【问题描述】:

同一目录下有两个模块。

我正在使用 Python 3.2

一个是a.py,像这样:

import b
class orig:
    def test(self):
        print("hello")


o = orig()
o.test()

另一个是b.py,像这样:

from a import orig
orig.test=lambda self: print("wrong")

当我运行这样的命令时:

python a.py

我希望在输出中只看到一个hello,但是,我在输出中看到了两个hello。每个hello 单独一行。

另外,我很困惑python如何处理两个模块相互导入的情况。

有人对此有想法吗?

【问题讨论】:

  • 一般应避免循环导入

标签: python oop dynamic module package


【解决方案1】:

当您直接运行python 脚本时,就像您对python a.py 所做的那样,python 解释器不会猜测该文件的模块路径应该是什么;它只是创建了一个名为 __main__ 的模块并运行它。

另一个微妙之处是每次python遇到导入时,它首先创建模块并将其存储在sys.modules中,以便同一模块的所有其他导入产生相同的模块对象。只有留下面包屑后,它才会开始执行实现该模块的 python 代码。

这就是发生的事情,一步一步,你在你的 shell 控制台上输入python a.py,python 创建一个__main__ 模块并开始评估该文件。

the file being parsed
  |
  |       the module being imported       
  |         |     
./a.py  __main__  1:  import b

好的,所以首先发生的是a.py 导入了一些东西。它以前从未导入过,所以它搜索路径并找到b.py;由于我们仍在尝试导入另一个文件,因此我将缩进一点以显示这一点。

    ./b.py  b  1:  from a import orig

b.py 中发生的第一件事是它尝试导入a。但a 也从未被导入;当python搜索路径时,它会找到a.py

        ./a.py  a  1:  import b

看起来很眼熟;但是 b 已经被导入了;这个b 将是同一个(仍在导入过程中!

        ./a.py  a  2:  class orig:
        ./a.py  a  3:      def test(self):
        ./a.py  a  4:          print("hello")
        ./a.py  a  5:  
        ./a.py  a  6:  
        ./a.py  a  7:  o = orig()
        ./a.py  a  8:  o.a()

好的。一个类被创建,实例化,并出现一些输出; a 现已完成导入;很好,因为 b 使用了 from 导入,这意味着 orig 现在需要存在,否则导入会失败。

    ./b.py  b  2:  orig.test=lambda self: print("wrong")

b猴子补丁a.orig(注意;不是__main__.orig)。 b 现在也导入完成了。

./a.py  __main__  2:  class orig:
./a.py  __main__  3:      def test(self):
./a.py  __main__  4:          print("hello")
./a.py  __main__  5:  
./a.py  __main__  6:  
./a.py  __main__  7:  o = orig()
./a.py  __main__  8:  o.a()

现在__main__ 正在定义一个类,实例化它并打印一些输出。另请注意,这是__main__.orig 类的定义,而不是修改后的a.orig b。

希望这能消除一些困惑。

【讨论】:

    【解决方案2】:

    你得到两行输出,因为你执行 a.py 两次:一次作为主程序,一次当它被导入到 b 中时。避免循环导入,绝对不要导入你的主程序。

    导入主程序的另一个副作用:您现在在这个程序中实际上有两个名为orig 的类。

    【讨论】:

      【解决方案3】:

      就第二个@TokenMacGuy 和@Ned:如果你将a.py 的结尾替换为:

      if __name__ == "__main__":
          o = orig()
          o.test()
      

      你只会得到一个“你好”。

      而且,确实:避免循环依赖!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-17
        • 1970-01-01
        • 2012-04-13
        • 2022-12-04
        • 2016-03-07
        • 1970-01-01
        • 2023-03-27
        相关资源
        最近更新 更多