【问题标题】:How can I import a package using __import__() when the package name is only known at runtime?当包名称仅在运行时已知时,如何使用 __import__() 导入包?
【发布时间】:2009-06-29 11:35:00
【问题描述】:

我有一个带有__init__.py 文件和另一个模块messages_en.py 的消息文件夹(包)。在__init__.py 中,如果我导入messages_en 它可以工作,但__import__ 失败并显示“ImportError:没有名为messages_en 的模块”

import messages_en # it works
messages = __import__('messages_en') # it doesn't ?

我曾经认为'import x'只是__import__('x')的另一种说法

【问题讨论】:

    标签: python python-import


    【解决方案1】:

    如果是路径问题,应该使用level参数(来自docs):

    __import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module
    
    Level is used to determine whether to perform
    absolute or relative imports.  -1 is the original strategy of attempting
    both absolute and relative imports, 0 is absolute, a positive number
    is the number of parent directories to search relative to the current module.
    

    【讨论】:

    • 但我想知道是什么原因,因为默认级别是-1,而我仍在通过-1,所以只有额外的全局/本地字典,这有什么不同
    • 为什么这是公认的答案?它既不回答问题也不解决问题。
    • 这个答案是错误的。 OP 的问题与level 没有任何关系。修复它的两个选项:要么像 Eric 指出的那样提供模块的全局变量 messages = __import__('messages_en', globals()),要么按照 Lennart 的建议给出包名称。
    • 在 Python 3 中,级别必须 >=0。在这种情况下将其设置为 1。
    【解决方案2】:

    添加 globals 参数对我来说就足够了:

    __import__('messages_en', globals=globals())
    

    其实这里只需要__name__

    __import__('messages_en', globals={"__name__": __name__})
    

    【讨论】:

    • 感谢globals={"__name__": __name__}
    【解决方案3】:

    __import__是import语句调用的内部函数。在日常编码中,您不需要(或不想)致电__import__

    来自 python 文档:

    例如,import spam 语句生成的字节码类似于以下代码:

    spam = __import__('spam', globals(), locals(), [], -1)
    

    另一方面,from spam.ham import eggs, sausage as saus 语句导致

    _temp = __import__('spam.ham', globals(), locals(), ['eggs', 'sausage'], -1)
    eggs = _temp.eggs
    saus = _temp.sausage
    

    更多信息: http://docs.python.org/library/functions.html

    【讨论】:

    • +1 并感谢您的解释,但是您能否准确描述一下为什么 OP 的示例不起作用?他似乎试图将messages_en别名为messages,这似乎(对我来说天真)是合理的。
    • 正如 'wr' 解释的那样,这是由于级别,我知道通常不应该使用 import 但在这种情况下,我必须从配置文件中动态读取语言附加到消息并导入该文件
    • 这个例子很有帮助,尤其是当你试图从子目录加载模块时。它帮助我修复了“找不到属性”错误。
    • @AnuragUniyal 不,由于缺少globals(),您的示例不起作用,level 的默认值很好。
    【解决方案4】:

    确保将模块目录附加到您的 python 路径。

    您的路径(Python 搜索模块和文件所经过的目录列表)存储在 sys 模块的路径属性中。由于路径是一个列表,您可以使用 append 方法将新目录添加到路径中。

    例如,将目录 /home/me/mypy 添加到路径中:

    import sys
    sys.path.append("/home/me/mypy") 
    

    【讨论】:

    • 这不安全,因为它使包不可重定位。只有当包在这个硬编码路径中时它才会起作用。
    【解决方案5】:

    我知道这个问题与__import__() 函数有关,但我认为importlib 包最适合运行时包导入,如果您按照doc 中的建议使用Python 2.7 或更高版本:

    注意:模块的程序化导入应该使用 import_module() 而不是这个函数。

    可能的问题:This was introduced in python 2.7:

    2.7 版中的新功能。

    此模块是 Python 3.1 中功能更全面的同名包中可用功能的一个小子集,它提供了完整的导入实现。此处提供的内容有助于轻松从 2.7 过渡到 3.1。

    在你的情况下,你可以使用:

    import importlib
    
    messages = importlib.import_module('messages_en')
    

    另外,如果你想指定包名,那么from messages import messages_en可以写成:

    importlib.import_module('.messages_en', 'messages')

    注意.messages_en 中的. 用于相对路径解析,如here 所述:

    ... name 参数以绝对或相对术语(例如 pkg.mod 或 ..mod)指定要导入的模块。如果名称以相对术语指定,则 package 参数必须设置为作为解析包名称的锚点的包名称(例如 import_module('..mod', 'pkg.subpkg')将导入 pkg.mod)。

    【讨论】:

    • 其他答案或假设都不再有效。感谢您的 importlib,Chukwuemeka!终于解决了我的一个问题!
    【解决方案6】:

    你可以试试这个:

    messages == __import__('Foo.messages_en', fromlist=['messages_en'])
    

    【讨论】:

      【解决方案7】:

      你需要手动导入你的动态包路径的顶层包。

      例如在我写的文件的开头:

      import sites
      

      然后在代码中这对我有用:

      target = 'some.dynamic.path'
      my_module = __import__ ('sites.%s.fabfile' % target, fromlist=["sites.%s" % target])
      

      【讨论】:

        猜你喜欢
        • 2010-10-01
        • 2023-01-26
        • 2019-02-23
        • 2012-10-16
        • 2021-07-26
        • 2021-05-06
        • 1970-01-01
        • 2018-01-21
        • 1970-01-01
        相关资源
        最近更新 更多