从子目录导入文件?


455

我的档案tester.py位于/project

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

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

我想导入BoxTimetester。我已经试过了:

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()

Answers:


536

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

简而言之,您需要放置一个名为

__init__.py

在“ lib”目录中。


59
为什么感觉很笨拙?这是python标记安全/可用导入目录的方式。
IAbstract 2014年

7
它不仅标记了安全/可用的导入目录,而且还提供了一种在导入目录名称时运行一些初始化代码的方法。
Sadjad 2014年

32
是的,这很容易破解,甚至很脏,我认为该语言不应强加其在整个文件系统中加载文件的方式。在PHP中,我们通过让用户态代码注册多个自动加载函数(当缺少名称空间/类时调用)来解决了该问题。然后,社区制定了PSR-4标准,Composer实施了该标准,如今没有人担心。而且没有愚蠢的硬编码__init__文件(但是,如果您愿意,只需注册一个自动加载的钩子即可!这是hackyhackable之间的区别)。
Morgan Touverey Quilling 2015年

4
@AurélienOomsimport sys, os; sys.path.insert(0, os.path.abspath('..')); from sibling_package.hacks import HackyHackHack
jbowman

4
python是一个凌乱的:)
Jimmy Pettersson

174
  • 创建一个名为的子目录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!

2
您能提供指向Python文档的链接吗?谢谢!
泽农


实现程序包的不错的演练lib
MasterControlProgram

请注意:subdirs不能包含破折号或点,但下划线有效。对我来说,这似乎与其他符号名称的限制相同,但我尚未深入到文档级别。
亚历山大·斯托尔

下划线=> python3(为时已晚,无法编辑注释)
Alexander Stohr

68

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

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

11
如果您由于某种原因无法或不会创建init .py文件,则此功能很好。
jpihl 2014年

1
如果您从“项目”目录中运行python,则此方法有效。“。” 是相对于您当前的工作目录而不是相对于您正在执行的文件所在目录的解释。说你cd /datapython ../project/tester.py。那就行不通了。
Morningstar 2014年

2
这对我有用。与init .py文件相比,我更喜欢这样做,它可以使导入语句更整洁。
泰勒·埃文森

5
这可以更好地工作,并且是“正确的”解决方案。 init .py弄乱了诸如boto之类的程序包,这些程序包具有自己的带有模块的子文件夹。
Dave Dopson

1
@jpihl您必须创建(至少)一个名为__init__.py的empy文件,以允许python从该文件夹导入模块。我已经尝试过该解决方案,并且效果很好(v2.7.6)。
m3nda

31

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

您无需命名子目录lib。你能说出它anything提供你把一个__init__.py进去。

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

$ touch anything/__init__.py 

所以现在您有了以下结构:

$ ls anything/
__init__.py
mylib.py

$ ls
main.py

然后,你可以导入mylibmain.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'。有什么事吗 PS: 我正在使用Django并尝试导入views.pyutils文件夹处于同一级别的文件夹
Jagruti,

可以在导入模块时使用绝对路径,并通过PYTHONPATH=. python path/to/program.py
nurettin '19

21

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

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


16

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


2
我认为我以前从未见过这种语法。是否有充分的理由(不是)使用此方法?
tgray

2
为什么这不是答案。当然,如果您想完成整个打包工作,则应该这样做。但这不是最初的问题。
特拉维斯·格里格斯

这给了我:ValueError:尝试以非打包方式进行相对导入
Alex

5
仅当您要导入的文件本身是软件包的一部分时,此方法才有效。如果没有,您将收到@Alex指出的错误。
乔纳森·莱因哈特

8

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

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()

2
如果您正在使用os.path,则可能要使用os.path.join((os.path.dirname(os.path.realpath(__file__)),'..','anotherproject')而不是在路径串联中对'/'进行硬编码。
Cowbert

你为什么不能"../anotherproject"没有它os.path.dirname()呢?
Moshe Rabaev '18年

@MosheRabaev-最好使用os.path函数。如果编写了“ ../anotherproject”并将代码移至Windows OS,则代码将中断!os.path utils知道如何考虑运行代码的操作系统返回正确的路径。有关更多信息docs.python.org/2/library/os.path.html
水星

@MosheRabaev,如果使用不带的“ ..” dirname(realpath(__file__)),则它将在运行脚本时计算相对于当前工作目录的路径,而不是相对于脚本所在的位置。
TJ Ellis

5

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

from __future__ import absolute_import 

然后

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

或更好

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

0

只是这些答案的补充。

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

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

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


-1

/project/tester.py

/project/lib/BoxTime.py

下一__init__.py行创建空白文件,直到找到文件

/project/lib/somefolder/BoxTime.py

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.