如何导入上面目录中的Python类?


Answers:


176

from ..subpkg2 import mod

根据Python文档:在包层次结构中,请使用两个点,如import语句 doc所述:

指定要导入的模块时,不必指定模块的绝对名称。当一个模块或程序包包含在另一个程序包中时,可以在同一顶部程序包中进行相对导入,而不必提及程序包名称。之后,通过在指定的模块或程序包中使用前导点,from可以指定在不指定确切名称的情况下遍历当前程序包层次结构的高度。一个前导点表示进行导入的模块所在的当前包。两点表示一个包装级别。三个点在两个级别上,依此类推。因此,如果from . import modpkg包中的模块执行,则最终将导入pkg.mod。如果from ..subpkg2 import mod从内部执行,pkg.subpkg1则将导入pkg.subpkg2.mod。相对进口的规范包含在PEP 328中

PEP 328处理绝对/相对进口。


4
up1 = os.path.abspath('..')sys.path.insert(0,up1)
rp。

Pep 328仅显示Python版本:2.4、2,5、2.6。第3版留给知识渊博的人使用。
吉梅尔18-3-13

22
这会触发错误ValueError:尝试相对顶级包进行相对导入
卡洛(Carlo)

4
ImportError中的结果:尝试进行相对导入,但没有已知的父包
Rotkiv

115
import sys
sys.path.append("..") # Adds higher directory to python modules path.

1
这对我有用。添加之后,我可以直接导入父模块,而无需使用“ ..”。
Evan Hu

8
粗略地说,只有当应用程序的PWD值(其当前的Directeroy)是父级的子级时,它才起作用。因此,即使它起作用,许多系统的更改也可能使其消失。
Phlip 2014年

这对我来说也适用于导入更高级别的模块。我将此与os.chdir(“ ..”)一起使用,以加载更高级别的其他文件。
Surendra Shrestha

这似乎触发与gimel的上述答案相同的错误。
卡罗

81

如果您可以保证他提到的软件包层次结构, @gimel的答案是正确的。如果您不能-如果您的真正需要如您所表达的那样,完全与目录绑定,并且与打包没有任何必要的关系-那么您需要__file__继续寻找父目录(几个os.path.dirname调用即可; - ),然后(如果该目录尚未上sys.path)预先准备暂时插入说,在非常的启动目录sys.path__import__,除去上述再DIR -事实上杂乱的工作,但是,“当你必须,你必须”(和Pyhon努力永不停止程序员做必须做的事情做的事情-就像ISO C标准在其序言中“ C的精神”部分中所说!!)。

这是一个可能适合您的示例:

import sys
import os.path
sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))

import module_in_parent_dir

2
这可能会 Python包添加一个目录,sys.path从而使相同的模块以不同的名称和所有相应的bug可用。pypy中的autopath.py或twisted中的_preamble.py通过使用搜索条件来解决它,该搜索条件在向上遍历目录时标识顶级包。
jfs

4
您可能想要sys.path.remove(pathYouJustAdded)在导入之后执行类似的操作,以免保留新路径。
Matthias

35

从当前目录正上方一层的目录中导入模块:

from .. import module

38
我得到:尝试了超出顶级软件包的相对导入:(
RicardoE

25
使用 from .. import module 我得到了错误ValueError:按照建议尝试在非软件包中进行相对导入
user3428154

4

如何加载目录中的模块

前言:我对以前的答案进行了实质性的重写,希望能够帮助人们轻松地进入python的生态系统,并希望通过python的导入系统为每个人带来最大的成功改变。

这将涵盖软件包中的相对进口,我认为这是OP问题最可能的情况。

Python是一个模块化系统

这就是为什么我们编写import foo从根名称空间加载模块“ foo”而不是编写的原因:

foo = dict();  # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh:  # please avoid doing this
    exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo)  # please avoid doing this

Python未与文件系统耦合

这就是为什么我们可以在没有实际文件系统的环境中嵌入python而无需提供虚拟文件系统(例如Jython)的原因。

与文件系统脱钩,可以灵活地进行导入,该设计允许从存档/ zip文件导入,导入单例,字节码缓存,cffi扩展,甚至远程代码定义加载。

因此,如果导入未与文件系统耦合,“向上目录”是什么意思?我们挑选出一些启发,但一中工作时,我们能做到这一点,例如包装,一些启发式已经被定义,使得像相对进口.foo..foo在同一封装内的工作。凉!

如果您真诚地希望将源代码加载模式耦合到文件系统,则可以这样做。您必须选择自己的试探法,并使用某种导入机制,我建议使用importlib

Python的importlib示例如下所示:

import importlib.util
import sys

# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'

foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)

foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton

打包

这里有一个很好的官方示例项目:https//github.com/pypa/sampleproject

python软件包是有关您的源代码的信息的集合,该软件包可以告知其他工具如何将您的源代码复制到其他计算机,以及如何将源代码集成到该系统的路径中,从而import foo适用于其他计算机(无论解释器,主机操作系统等)

目录结构

让我们foo在某个目录(最好是空目录)中有一个包名。

some_directory/
    foo.py  # `if __name__ == "__main__":`  lives here

我的首选是创建setup.py与的兄弟姐妹foo.py,因为它使setup.py文件的编写更加简单,但是您可以编写配置来更改/重定向setuptools默认情况下愿意做的一切;例如放在foo.py“ src /”目录下比较流行,这里不做介绍。

some_directory/
    foo.py
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    py_modules=['foo'],
)

python3 -m pip install --editable ./  # or path/to/some_directory/

“可编辑” -e又将再次重定向导入机制,以将源文件加载到此目录中,而不是将当前的确切文件复制到安装环境的库中。这也可能导致开发人员机器上的行为差异,请务必测试您的代码!除了pip之外,还有其他工具,但是我建议您将pip用作入门工具:)

我还想制作foo一个“包”(包含的目录__init__.py)而不是一个模块(一个“ .py”文件),“包”和“模块”都可以加载到根名称空间中,模块允许嵌套名称空间,如果我们要进行“相对一个目录向上”导入,这将很有帮助。

some_directory/
    foo/
        __init__.py
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
)

我也喜欢做一个foo/__main__.py,这允许python将包作为模块python3 -m foo执行,例如将foo/__main__.py作为__main__

some_directory/
    foo/
        __init__.py
        __main__.py  # `if __name__ == "__main__":`  lives here, `def main():` too!
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
    ...
    entry_points={
        'console_scripts': [
            # "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
            'foo=foo.__main__:main',
        ]
    },
)

让我们用更多的模块充实一下:基本上,您可以拥有一个目录结构,如下所示:

some_directory/
    bar.py           # `import bar`
    foo/
        __init__.py  # `import foo`
        __main__.py
        baz.py       # `import foo.baz
        spam/           
            __init__.py  # `import foo.spam`
            eggs.py      # `import foo.spam.eggs`
    setup.py

setup.py 按照惯例,其中包含有关源代码的元数据信息,例如:

  • 安装名为“ install_requires”所需的依赖项
  • 软件包管理应使用什么名称(安装/卸载“名称”),在我们的案例中,建议与主python软件包名称匹配 foo,,尽管用下划线代替连字符很普遍
  • 许可信息
  • 成熟度标签(alpha / beta / etc),
  • 受众标签(用于开发人员,用于机器学习等),
  • 单页文档内容(如自述文件),
  • 外壳程序名称(您在用户外壳程序上键入的名称(如bash)或在图形用户外壳程序中找到的名称(如开始菜单)),
  • 该软件包将安装(和卸载)的python模块列表
  • 实际的“运行测试”入口点 python ./setup.py test

它非常广泛,如果在开发机器上安装了源模块,它甚至可以即时编译c扩展。对于每天的示例,我建议使用PYPA样本存储库的setup.py

如果要发布构建工件(例如,旨在运行几乎相同的计算机的代码副本),则requests.txt文件是用于快照确切的依赖项信息的一种流行方法,其中“ install_requires”是捕获最小数量和最小数量的好方法。最高兼容版本。但是,无论如何目标计算机几乎都是相同的,我强烈建议创建一个完整的python前缀的tarball。这可能很棘手,太详细了,无法在此处介绍。签出pip install--target签选项,或virtualenv aka venv寻找线索。

回到例子

如何在一个目录下导入文件:

在foo / spam / eggs.py中,如果需要foo / baz中的代码,我们可以通过其绝对名称空间来请求它:

import foo.baz

如果我们想保留将来通过其他一些相对baz实现将eggs.py移到其他目录的功能,可以使用相对导入,例如:

import ..baz

-5

Python是一个模块化系统

Python不依赖文件系统

为了可靠地加载python代码,请将该代码放在模块中,然后将该模块安装在python的库中。

已安装的模块始终可以通过以下方式从顶级名称空间加载: import <name>


这里有一个很好的示例项目正式可用:https : //github.com/pypa/sampleproject

基本上,您可以具有如下目录结构:

the_foo_project/
    setup.py  

    bar.py           # `import bar`
    foo/
      __init__.py    # `import foo`

      baz.py         # `import foo.baz`

      faz/           # `import foo.faz`
        __init__.py
        daz.py       # `import foo.faz.daz` ... etc.

一定要声明你setuptools.setup()setup.py

官方示例:https//github.com/pypa/sampleproject/blob/master/setup.py

在我们的例子中,我们可能想导出bar.pyfoo/__init__.py我的简短示例:

setup.py

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    ...
    py_modules=['bar'],
    packages=['foo'],
    ...
    entry_points={}, 
        # Note, any changes to your setup.py, like adding to `packages`, or
        # changing `entry_points` will require the module to be reinstalled;
        # `python3 -m pip install --upgrade --editable ./the_foo_project
)

现在我们可以将模块安装到python库中;使用pip,您可以the_foo_project在编辑模式下安装到python库中,因此我们可以实时对其进行处理

python3 -m pip install --editable=./the_foo_project

# if you get a permission error, you can always use 
# `pip ... --user` to install in your user python library

现在,从任何python上下文中,我们都可以加载共享的py_modules和包

foo_script.py

#!/usr/bin/env python3

import bar
import foo

print(dir(bar))
print(dir(foo))

2
应该提到的是,我在使用时总是会安装模块pip install --edit foo,几乎总是在virtualenv内。我几乎从未写过不打算安装的模块。如果我误解了一些我想知道的事情。
ThorSummoner '16

我还要提到的是,使用venv-auto-creation测试套件(例如tox)非常有用,因为editableegg链接和安装的python模块在每种方式上都不完全相同;例如,将在路径查找中找到将新名称空间添加到可编辑模块的方法,但是如果未在setup.py文件中导出该名称空间,则将不会打包/安装该名称空间!测试您的用例:)
ThorSummoner
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.