【问题标题】:In python, questions on importing a module that import another module?在 python 中,关于导入另一个模块的模块的问题?
【发布时间】:2018-10-02 07:13:36
【问题描述】:

我是python初学者,目前正在学习python中的导入模块。 所以我的问题是: 假设我目前有三个python文件,分别是module1.py、module2.py和module3.py;

在module1.py中:

def function1():
    print('Hello')

在module2.py中,为了使用module1.py中的那些函数:

import module1

#Also, I have some other public functions in this .py file
def function2():
    print('Goodbye')

#Use the function in module1.py
if __name__ == '__main__':
    module1.function1();
    function2();

在module3.py中,我想同时使用module1.py和module2.py中的函数。

import module1
import module2

def function3():
    print('Nice yo meet you');

if __name__ == '__main__':
   module1.function1()
   function3()
   module2.function2()

似乎有效。但我的问题主要是关于module3.py。原因是在module3.py中,我同时导入了module1和module2。但是,module1 已经由 module2 导入。我只是想知道这是否是一种编码的好方法?这有效吗?我应该这样做吗?或者我应该避免这样做吗?为什么?

非常感谢。我只是一个初学者,所以如果我问愚蠢的问题,请原谅我。谢谢!!

【问题讨论】:

  • 请看我的回答编辑。

标签: python python-3.x


【解决方案1】:

如果你避免循环导入就没有问题,也就是说你永远不会导入一个本身导入当前导入模块的模块。

模块看不到导入器命名空间,因此导入器代码中的导入不会成为导入模块的全局变量。

此外,模块顶级代码仅在首次导入时运行。


编辑 1:

我在这里回答 Filipe 的 cmets,因为它更容易。

“避免循环导入就没有问题” -> 这是不正确的,python 在大多数情况下都可以使用循环导入。”

您感觉到我的一些误解这一事实并不意味着该特定陈述不正确。这是正确的,也是很好的建议。

(说大部分时间都很好看起来有点像说某事会在大多数情况下运行良好......)

我明白你的意思。我非常避免它,以至于我什至认为您的第一个示例会立即给出错误(它没有)。你的意思是没有必要避免它,因为大多数时候(实际上在某些条件下)Python 会很好地处理它。我也确信在某些情况下循环导入将是最简单的解决方案。这并不意味着我们应该在有选择的情况下使用它们。这将促进使用糟糕的架构,每个模块都开始依赖于其他模块。

这也意味着编码人员必须了解这些警告。

我在 SO 中找到的这个链接 here 陈述了对循环导入的一些担忧。

之前的链接有些旧,因此信息可能会被较新的 Python 版本过时,但 import confusion 甚至更旧,仍然适用于 3.6.2。

您提供的示例运行良好,因为相关或初始化模块代码被包装在一个函数中,并且不会在导入时运行。使用if __name__ == "__main__": 保护代码也会在导入时将其从运行中移除。

像这样简单的东西(来自 effbot.org 的同一个例子)是行不通的(记住 OP 说他是初学者):

# file y.py
import x

x.func1()


# file x.py
import y

def func1():
    print('printing from x.func1')

在您的第二条评论中,您说: “这也是不正确的。导入的模块将成为命名空间的一部分”

是的。但我没有提到这一点,也没有相反。我刚刚说过导入的模块代码不知道进行导入的代码的命名空间。

为了消除歧义,我的意思是这样的:

# w.py
def funcw():
    print(z_var)

# z.py
import w

z_var = 'foo'
w.funcw() # error: z_var undefined in w module namespace

运行z.py 会给出所述错误。这就是我的意思。

现在更进一步,为了获得我们想要的访问权限,我们循环...

# w.py
import z # go circular

def funcw():
    '''Notice that we gain access not to the z module that imported
       us but to the z module we import (yes its the same thing but
       carries a different namespace). So the reference we obtain
       points to a    different object, because it really is in a
       different namespace.'''

    print(z.z_var, id(z.z_var))

...我们保护一些代码不与导入一起运行:

# z.py
import w

z_var = ['foo']

if __name__ == '__main__':
    print(z_var, id(z_var))
    w.funcw()

通过运行z.py,我们确认对象是不同的(它们可以与不可变对象相同,但这是python kerning - 内部优化或实现细节 - 起作用):

['foo'] 139791984046856
['foo'] 139791984046536

最后我同意你关于明确导入的第三条评论。

无论如何,我感谢您的 cmets。因为他们,我实际上提高了我对问题的理解(我们并没有通过避免它来学到很多东西)。

【讨论】:

  • "如果你避免循环导入就不会有问题" -> 这是不正确的,python 在大多数情况下都可以使用循环导入。例如,如果 module1.py 有 import module3 并且 function1 调用 module3.function3() 一切都会正常工作。
  • "模块看不到导入器命名空间,因此导入器代码中的导入不会成为导入模块的全局变量。" -> 这也是不正确的。导入的模块将成为命名空间的一部分。因此,在 module3.py 中,即使不导入 module1,您也可以使用 module2.module1.function1() 调用 function1。
  • 话虽如此,明确的依赖关系是一个很好的建议。最好避免通过另一个导入该模块的模块来引用该模块。
  • @FilipeBrandenburger 我试图改进我的答案,如果您发现有问题,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
  • 2020-05-18
  • 2022-01-08
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多