【问题标题】:Import a file from a subdirectory?从子目录导入文件?
【发布时间】:2010-11-18 15:34:07
【问题描述】:

我有一个名为tester.py 的文件,位于/project

/project 有一个名为lib 的子目录,以及一个名为BoxTime.py 的文件:

/project/tester.py
/project/lib/BoxTime.py

我想从tester 导入BoxTime。我试过这个:

import lib.BoxTime

结果:

Traceback (most recent call last):
  File "./tester.py", line 3, in <module>
    import lib.BoxTime
ImportError: No module named lib.BoxTime

任何想法如何从子目录中导入BoxTime

编辑

__init__.py 是问题所在,但不要忘记将BoxTime 称为lib.BoxTime,或使用:

import lib.BoxTime as BT
...
BT.bt_function()

【问题讨论】:

  • 好像他正在导入lib/BoxTime to tester

标签: python python-import


【解决方案1】:

看看Packages documentation (Section 6.4)

总之,你需要放一个名为

的空白文件
__init__.py

lib 目录中。

【讨论】:

  • 为什么感觉 hacky?这是 python 标记安全/可用导入目录的方式。
  • 它不仅标记了安全/可用的导入目录,还提供了在导入目录名称时运行一些初始化代码的方法。
  • 是的,这很hacky,甚至很脏,在我看来,该语言不应该强加其在文件系统中加载文件的方式。在 PHP 中,我们通过让用户空间代码注册多个在命名空间/类丢失时调用的自动加载函数来解决这个问题。然后社区产生了 PSR-4 标准并由 Composer 实现,现在没有人担心这个。并且没有愚蠢的硬编码 __init__ 文件(但如果你想要它,只需注册一个自动加载钩子!这就是 hackyhackable 之间的区别)。
  • @YaShChaudhary 在我更改对库的引用之前它对我不起作用:文件夹名称.模块名称
  • 必要的__init__.py 文件至少不舒服,不管它是否是hacky。而这一点在 Python 3.3 中得到了解决:可以在没有文件的情况下组成包。
【解决方案2】:

试试import .lib.BoxTime。有关更多信息,请阅读 PEP 328 中的相对导入。

【讨论】:

  • 我认为我以前从未见过这种语法。是否有充分的理由(不)使用这种方法?
  • 为什么不是这个答案。当然,如果你想做整个包的事情,你应该这样做。但这不是最初的问题。
  • 这给了我:ValueError: Attempted relative import in non-package
  • 这仅在您要从中导入的文件本身是包的一部分时才有效。如果没有,您将收到@Alex 指出的错误。
【解决方案3】:

您的 lib 目录是否包含 __init__.py 文件?

Python 使用__init__.py 来确定目录是否为模块。

【讨论】:

    【解决方案4】:
    • 创建一个名为lib的子目录。
    • 创建一个名为lib\__init__.py的空文件。
    • lib\BoxTime.py 中,像这样写一个函数foo()

      def foo():
          print "foo!"
      
    • lib上面的目录中你的客户端代码中,写:

      from lib import BoxTime
      BoxTime.foo()
      
    • 运行您的客户端代码。你会得到:

      foo!
      

    很久以后 -- 在 linux 中,它看起来像这样:

    % cd ~/tmp
    % mkdir lib
    % touch lib/__init__.py
    % cat > lib/BoxTime.py << EOF
    heredoc> def foo():
    heredoc>     print "foo!"
    heredoc> EOF
    % tree lib
    lib
    ├── BoxTime.py
    └── __init__.py
    
    0 directories, 2 files
    % python 
    Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
    [GCC 4.8.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from lib import BoxTime
    >>> BoxTime.foo()
    foo!
    

    【讨论】:

    • 您能否提供一个指向解释此问题的 Python 文档的链接?谢谢!
    • 让我们将该链接设为可点击:docs.python.org/3/tutorial/modules.html#packages
    • 很好的实现包的演练lib
    • 请注意:子目录不得包含破折号或圆点,但下划线有效。对我来说,这似乎与其他符号名称的限制相同,但我尚未将其深入到文档级别。
    • 下划线 => python3(来不及编辑评论)
    【解决方案5】:

    你可以试试插入sys.path:

    sys.path.insert(0, './lib')
    import BoxTime
    

    【讨论】:

    • 如果您由于某种原因不能或不会创建 init.py 文件,那就太好了。
    • 如果你从“项目”目录运行 python,它就可以工作。这 ”。”相对于您当前的工作目录进行解释,而不是相对于您正在执行的文件所在的目录。说你cd /datapython ../project/tester.py。然后就不行了。
    • 这对我有用。与 init.py 文件相比,我更喜欢它,它使导入语句更清晰。
    • 这工作得更好,是“正确”的解决方案。 init.py 搞乱了像 boto 这样的包,这些包有自己的子文件夹和模块。
    • @jpihl 您必须(至少)创建一个名为 __init__.py 的 empy 文件以允许从该文件夹导入 python 模块。我已经尝试过该解决方案并且效果很好(v2.7.6)。
    【解决方案6】:

    试试这个:

    from lib import BoxTime

    【讨论】:

    • 没有任何解释,这不是很有用。
    【解决方案7】:

    包含完整示例

    这基本上涵盖了所有情况(确保您在 relative/path/to/your/lib/folder 中有 __init__.py):

    import sys, os
    sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/your/lib/folder")
    import someFileNameWhichIsInTheFolder
    ...
    somefile.foo()
    

    示例:

    您的项目文件夹中有:

    /root/myproject/app.py
    

    您在另一个项目文件夹中:

    /root/anotherproject/utils.py
    /root/anotherproject/__init__.py
    

    您想使用/root/anotherproject/utils.py 并调用其中的 foo 函数。

    所以你在 app.py 中写:

    import sys, os
    sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../anotherproject")
    import utils
    
    utils.foo()
    

    【讨论】:

    • 如果您使用os.path,您可能希望使用os.path.join((os.path.dirname(os.path.realpath(__file__)),'..','anotherproject'),而不是硬编码路径连接中的“/”。
    • 为什么你不能在没有os.path.dirname() 的情况下只做"../anotherproject"
    • @MosheRabaev - 使用 os.path 函数是一个好习惯。如果编写“../anotherproject”并将代码移动到 Windows 操作系统,代码将中断! os.path utils 知道如何根据运行代码的操作系统返回正确的路径。欲了解更多信息docs.python.org/2/library/os.path.html
    • @MosheRabaev 如果您使用“..”而没有 dirname(realpath(__file__)),那么它将在您运行脚本时计算相对于您当前工作目录的路径,而不是相对于脚本所在的位置。
    【解决方案8】:

    在子目录 /lib 中创建一个空文件 __init__.py。 并在主代码开头添加

    from __future__ import absolute_import 
    

    然后

    import lib.BoxTime as BT
    ...
    BT.bt_function()
    

    或更好

    from lib.BoxTime import bt_function
    ...
    bt_function()
    

    【讨论】:

    • 这是在 Pycharm 中对我有用的唯一正确修复,谢谢
    【解决方案9】:

    /project/tester.py

    /project/lib/BoxTime.py

    创建空白文件__init__.py 直到你到达文件

    /project/lib/somefolder/BoxTime.py

    #lib -- 需要有两个项目一个 __init__.py 和一个名为 somefolder 的目录 #somefolder 有两个项目 boxtime.py__init__.py

    【讨论】:

      【解决方案10】:

      我写下来是因为似乎每个人都建议你必须创建一个lib 目录。

      您无需将子目录命名为 lib。您可以将其命名为 anything,前提是您将 __init__.py 放入其中。

      您可以通过在 linux shell 中输入以下命令来做到这一点:

      $ touch anything/__init__.py 
      

      所以现在你有了这个结构:

      $ ls anything/
      __init__.py
      mylib.py
      
      $ ls
      main.py
      

      然后您可以像这样将mylib 导入main.py

      from anything import mylib 
      
      mylib.myfun()
      

      你也可以像这样导入函数和类:

      from anything.mylib import MyClass
      from anything.mylib import myfun
      
      instance = MyClass()
      result = myfun()
      

      您放置在__init__.py 中的任何变量函数或类也可以被访问:

      import anything
      
      print(anything.myvar)
      

      或者像这样:

      from anything import myvar
      
      print(myvar)
      

      【讨论】:

      • 我的文件夹结构是utils\__init__.pyutils\myfile.py。 (实用程序包含两个文件)这就是我尝试导入from utils.myfile import myMethod 的方式。但我得到ModuleNotFoundError: No module named 'utils'。有什么问题? P.S:我正在使用Django 并尝试导入与utils 文件夹处于同一级别的views.py
      • 在导入模块时可以使用绝对路径并使用PYTHONPATH=. python path/to/program.py运行程序
      • 最清楚的答案!谢谢
      【解决方案11】:

      只是对这些答案的补充。

      如果您想从所有子目录导入所有文件,您可以将其添加到文件的根目录。

      import sys, os
      sys.path.extend([f'./{name}' for name in os.listdir(".") if os.path.isdir(name)])
      

      然后您可以简单地从子目录中导入文件,就像这些文件在当前目录中一样。

      工作示例

      如果我的项目中有以下带有子目录的目录...

      .
      ├── a.py
      ├── b.py
      ├── c.py
      ├── subdirectory_a
      │   ├── d.py
      │   └── e.py
      ├── subdirectory_b
      │   └── f.py
      ├── subdirectory_c
      │   └── g.py
      └── subdirectory_d
          └── h.py
      

      我可以将以下代码放入我的a.py 文件中

      import sys, os
      sys.path.extend([f'./{name}' for name in os.listdir(".") if os.path.isdir(name)])
      
      # And then you can import files just as if these files are inside the current directory
      
      import b
      import c
      import d
      import e
      import f
      import g
      import h
      

      换句话说,这段代码将抽象出文件来自哪个目录。

      【讨论】:

      • 嘿!我将您的一个衬里修改为sys.path.extend([f'{item[0]}' for item in os.walk(".") if os.path.isdir(item[0])]),现在它从项目目录中递归地刮取。谢谢您的回答!超级好用。
      • @Shrout1,干得好!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 2013-05-22
      • 2011-07-05
      • 1970-01-01
      相关资源
      最近更新 更多