【问题标题】:Python - when is 'import' required?Python - 什么时候需要“导入”?
【发布时间】:2010-11-04 21:09:09
【问题描述】:

mod1.py

import mod2

class Universe:
    def __init__(self):
        pass
    def answer(self):
        return 42

u = Universe()
mod2.show_answer(u)

mod2.py

#import mod1 -- not necessary
def show_answer(thing):
    print thing.answer()

来自 C++ 背景,我觉得有必要在 show_answer 函数起作用之前导入包含 Universe 类定义的模块。 IE。一切都必须先声明后才能使用。

我认为这没有必要是对的吗?这是鸭子打字,对吧?因此,如果不需要导入来查看类的方法,我至少需要它来用于类定义本身和模块的顶级函数?

在我编写的一个脚本中,我什至编写了一个基类来声明一个带有一组方法的接口,然后派生出具体的类来继承该接口,但我想我现在明白了——那就是在 Python 中是错误的,并且在运行时在调用时检查对象是否具有特定方法?

我意识到 Python 所以比 C++ 动态得多,我花了一段时间才知道您实际上需要编写多少代码!

我想我知道这个问题的答案,但我只是想澄清一下并确保我走在正确的轨道上。

更新:感谢所有答案,我想我现在应该澄清我的问题:

mod2.show_answer() 是否需要导入(任何描述)才能知道该事物有一个名为 answer() 的方法,还是在运行时动态确定?

【问题讨论】:

  • 回答你第二个问题:不,它是动态的。它会在 thing.__dict__ 中查找“答案”条目。在docs.python.org/reference/… 中查找“类实例”

标签: python import module


【解决方案1】:

我对C++了解不多,所以不能直接比较,但是..

import 基本上将另一个 Python 脚本(mod2.py)加载到当前脚本(mod1.py 的顶层)中。与其说是链接,倒不如说是eval

例如,在 Python 的伪代码中:

eval("mod2.py")

和..一样

from mod2 import *

..它执行 mod2.py,并使当前脚本中定义的函数/类可访问。

上面的 sn-ps 都可以让你调用show_answer()(嗯,eval 不太像那样工作,所以我称之为伪代码!)

import mod2

..基本上是一样的,但是不是将所有功能都带入“顶层”,而是将它们带入mod2模块,因此您可以通过调用show_answer..

mod2.show_answer

我是否认为 [mod2.py 中的导入] 没有必要?

当然。事实上,如果你尝试从mod2 导入mod1,你会得到一个循环依赖错误(因为mod2 然后尝试导入mod1 等等..)

【讨论】:

    【解决方案2】:

    Python 中的 import 将模块加载到给定的命名空间中。因此,是否好像 def show_answer 实际上存在于 mod1.py 模块中。因此,mod2.py 不需要知道 Universe 类,因此您不需要从 mod2.py 导入 mod1。

    【讨论】:

    • 不,不是因为导入发生在 Universe 类的定义之前。
    • 我的意思有点用错了,我会改正为我的意思。
    【解决方案3】:

    import 是关于名称的——主要是绑定在某个模块中的顶级(AKA 全局级别,AKA 模块级别名称)的“裸名”,例如 mod2。当您完成import mod2 后,您将获得mod2 命名空间作为可用名称(您自己的模块中的顶级名称,如果您将import 本身作为顶级名称,这是最常见的;但是函数内的本地import 将使mod2 成为该函数的局部变量,等等);因此您可以使用mod2.foobar 访问绑定在mod2 顶层的名称foobar。如果您不需要访问这些名称,那么您无需在自己的模块中使用import mod2

    【讨论】:

      【解决方案4】:

      事实上,根据this explanation ,循环import 不会按照您希望的方式工作:如果您取消注释import mod1,第二个模块仍然不知道Universe

      我认为这很合理。如果您的两个文件都需要访问某些特定对象的类型,例如Universe,您有多种选择:

      • 如果您的程序很小,只需使用一个文件
      • 如果它很大,您需要确定您的文件是否都需要知道Universe 是如何实现的,也许将未知类型的对象传递给show_answer 就可以了
      • 如果这对您不起作用,请务必将 Universe 放在单独的模块中并先加载它。

      【讨论】:

      • 是的,很抱歉循环导入,这是我的错误。不过,我的问题是:mod2 不需要 是否需要知道 Universe 是如何实现的?只要有一个 answer() 方法,我也可以将一个 ExamQuestion 对象传递给 show_answer?
      • 是的。就是这样。我认为这使 Python 更容易理解。尽管有些人抱怨这使得在错误类型上调用方法时出错成为可能,但我还没有在实践中看到这一点。
      【解决方案5】:

      实际上,在这种情况下,在mod2.py 中导入mod1 应该起作用。
      它不会创建循环引用吗?

      【讨论】:

      • 确实如此,在我的回答中的链接中查看更多信息。
      • 哎呀,是的,你是对的。我把示例代码删减了太多。试着想象一下 Universe 类是在一个单独的模块中!
      【解决方案6】:

      在这种情况下你是对的:show_answer() 被赋予一个对象,它调用方法“answer”。只要给 show_answer() 的对象有这样的方法,对象来自哪里都没有关系。

      但是,如果您想在 mod2 中创建 Universe 的实例,则必须导入 mod1,因为 Universe 不在 mod2 命名空间中,即使 mod1 已导入 mod2。

      【讨论】:

      • 确实,尽管有一些方法可以绕过它——mod1 类可以将 Universe 对象传递给 mod2,如果需要,它可以创建更多实例。
      【解决方案7】:

      认为导入更像是链接器。
      使用“import mod2”你只是告诉python它可以在文件mod2.py中找到函数

      【讨论】:

      • 请记住,导入发生在运行时。没有编译时间。你没有宣布一切。您只需提供一种解析名称的方法。
      • 这有关系吗?导入只是告诉虚拟机要查看哪个文件,执行此操作时没有任何区别。
      • 将导入基本上视为整个文件的#include 的组合,并更改名称 xxx -> mod.xxx
      • 但是 - 我认为这确实是我的问题 - 我是否需要导入 show_answer 才能知道它的参数有 answer() 方法?
      • @Steve,不,您可以尝试在任何对象上调用任何方法,并且它会成功,因为该对象碰巧具有该方法,无论出于何种原因。
      猜你喜欢
      • 2015-10-08
      • 2012-12-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-11
      相关资源
      最近更新 更多