从子目录导入文件?

Ada*_*tan 415 python module python-import subdirectory

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

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

/project/tester.py
/project/lib/BoxTime.py
Run Code Online (Sandbox Code Playgroud)

我想导入BoxTimetester.我试过这个:

import lib.BoxTime
Run Code Online (Sandbox Code Playgroud)

结果如下:

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

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

编辑

__init__.py是问题,但不要忘了提及BoxTime作为lib.BoxTime,或使用:

import lib.BoxTime as BT
...
BT.bt_function()
Run Code Online (Sandbox Code Playgroud)

Gre*_*reg 497

请查看Packages文档(第6.4节):http://docs.python.org/tutorial/modules.html

简而言之,您需要将一个空白文件命名为

__init__.py
Run Code Online (Sandbox Code Playgroud)

在"lib"目录中.

  • 为什么感觉*hacky*?这是python标记安全/可用导入目录的方式. (57认同)
  • 是的,这是hacky甚至是脏的,在我看来语言不应强加在文件系统中加载文件的方式.在PHP中,我们通过让userland代码注册多个自动加载函数来解决问题,这些函数在缺少名称空间/类时被调用.然后社区制定了PSR-4标准,Composer实现了它,现在没有人会担心这一点.并没有愚蠢的硬编码`__init__`文件(但如果你想要它,只需注册一个自动加载钩子!这是_hacky_和_hackable_之间的区别). (28认同)
  • 它不仅标记安全/可用的导入目录,还提供了在导入目录名时运行某些初始化代码的方法. (7认同)
  • @AurélienOoms`importsys,os; sys.path.insert(0,os.path.abspath('..')); 来自sibling_package.hacks导入HackyHackHack` (4认同)
  • 必要的“__init__.py”文件至少不舒服,不管它是否是hacky。而这一点在Python 3.3中得到了解决:没有文件也可以组成一个包。 (4认同)
  • python是一个凌乱的:) (2认同)
  • 另请参阅/sf/ask/2599785051/ (2认同)

hug*_*own 152


很久以后 - 在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!
Run Code Online (Sandbox Code Playgroud)

  • 让我们点击链接:https://docs.python.org/3/tutorial/modules.html#packages (5认同)
  • 您可以提供指向Python文档的链接吗?谢谢! (2认同)

Kre*_*mir 61

您可以尝试将其插入sys.path:

sys.path.insert(0, './lib')
import BoxTime
Run Code Online (Sandbox Code Playgroud)

  • 如果由于某种原因不能或不会创建__init__.py文件,这很好. (8认同)
  • 这工作得更好,是"正确"的解决方案.__init__.py搞乱像boto这样的软件包,它们有自己的子文件夹和模块. (5认同)
  • 如果您从“项目”目录运行 python,它会起作用。这 ”。” 相对于您当前的工作目录进行解释,而不是相对于您正在执行的文件所在的目录。假设你`cd /data`,`python ../project/tester.py`。那么它就行不通了。 (2认同)
  • 这对我有用.我更喜欢这个*init*.py文件,它使得更干净的import语句. (2认同)

nur*_*tin 25

我写这篇文章是因为每个人似乎都建议你必须创建一个lib目录.

您无需为子目录命名lib.你可以anything__init__.py它命名为它.

您可以通过在linux shell中输入以下命令来实现:

$ touch anything/__init__.py 
Run Code Online (Sandbox Code Playgroud)

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

$ ls anything/
__init__.py
mylib.py

$ ls
main.py
Run Code Online (Sandbox Code Playgroud)

然后,你可以导入mylibmain.py这样的:

from anything import mylib 

mylib.myfun()
Run Code Online (Sandbox Code Playgroud)

您还可以导入这样的函数和类:

from anything.mylib import MyClass
from anything.mylib import myfun

instance = MyClass()
result = myfun()
Run Code Online (Sandbox Code Playgroud)

__init__.py也可以访问放在里面的任何变量函数或类:

import anything

print(anything.myvar)
Run Code Online (Sandbox Code Playgroud)

或者像这样:

from anything import myvar

print(myvar)
Run Code Online (Sandbox Code Playgroud)

  • 我的文件夹结构是“utils\__init__.py”和“utils\myfile.py”。(Utils 包含这两个文件)这就是我尝试导入“from utils.myfile import myMethod”的方式。但我得到“ModuleNotFoundError:没有名为“utils”的模块”。可能出什么问题了?**PS:** 我正在使用 `Django` 并尝试导入与 `utils` 文件夹处于同一级别的 `views.py` (2认同)

小智 20

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

Python用于__init__.py确定目录是否为模块.


drr*_*lvn 15

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

  • 这仅适用于您从中导入的文件本身是程序包的一部分.如果没有,您将收到@Alex指出的错误. (5认同)
  • 我认为我以前从未见过这种语法.有没有强烈的理由(不)使用这种方法? (2认同)
  • 为什么这不是答案。当然,如果你想做整个包的事情,你应该这样做。但这不是最初的问题。 (2认同)

Mer*_*ury 7

我这样做基本上涵盖了所有情况(确保你__init__.py在relative/path/to/your/lib /文件夹中):

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


示例:
您在项目文件夹中:

/root/myproject/app.py
Run Code Online (Sandbox Code Playgroud)

你有另一个项目文件夹:

/root/anotherproject/utils.py
/root/anotherproject/__init__.py
Run Code Online (Sandbox Code Playgroud)

你想使用/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()
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用的是`os.path`,则可能要使用`os.path.join((os.path.dirname(os.path.realpath(__ file __)),'..','anotherproject')`)代替硬编码路径串联中的“ /”。 (2认同)

小智 6

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

from __future__ import absolute_import 
Run Code Online (Sandbox Code Playgroud)

然后

import lib.BoxTime as BT
...
BT.bt_function()
Run Code Online (Sandbox Code Playgroud)

或更好

from lib.BoxTime import bt_function
...
bt_function()
Run Code Online (Sandbox Code Playgroud)


Vic*_*tor 6

只是对这些答案的补充。

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

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

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

工作示例

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

.
??? a.py
??? b.py
??? c.py
??? subdirectory_a
?   ??? d.py
?   ??? e.py
??? subdirectory_b
?   ??? f.py
??? subdirectory_c
?   ??? g.py
??? subdirectory_d
    ??? h.py
Run Code Online (Sandbox Code Playgroud)

我可以将以下代码放入我的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
Run Code Online (Sandbox Code Playgroud)

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