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

时间:2009-06-28 04:56:26

标签: python module directory python-import

我想从位于当前目录之上的目录中的文件中继承。

是否可以相对导入该文件?

9 个答案:

答案 0 :(得分:153)

在包层次结构中,使用两个点,import statement doc说:

  

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

PEP 328涉及绝对/相对进口。

答案 1 :(得分:89)

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

答案 2 :(得分:69)

@ gimel的回答是正确的如果你可以保证他提到的包层次结构。如果你不能 - 如果你的真正需要是你所表达的,完全依赖于目录而与包装没有任何必要的关系 - 那么你需要在__file__上找到父目录(一对夫妇) os.path.dirname调用会做;-),然后(如果该目录尚未在sys.path上)prepend临时插入所述目录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

答案 3 :(得分:34)

从目录中导入模块,该目录与当前目录完全相同:

from .. import module

答案 4 :(得分:5)

如何加载目录目录中的模块

前言:我对以前的答案进行了实质性的重写,希望能够帮助人们轻松地进入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扩展名甚至远程代码定义加载。

因此,如果导入未与文件系统耦合,“向上目录”是什么意思?我们必须选择一些启发式方法,但是我们可以做到这一点,例如,在package中工作时,已经定义了一些启发式方法,这些方法使relative imports like .foo and ..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 foofoo/__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”需要什么依赖项
  • 应该使用什么名称进行软件包管理(安装/卸载“名称”),我建议在我们的案例foo中,此名称与您的主要python软件包名称匹配,尽管用下划线代替连字符很受欢迎
  • 许可信息
  • 成熟度标签(alpha / beta /等)
  • 受众标签(用于开发人员,用于机器学习等)
  • 单页文档内容(如自述文件)
  • shell名称(您在用户shell上键入的名称(例如bash)或在图形用户shell中找到的名称(例如开始菜单)
  • 此软件包将安装(和卸载)的python模块列表
  • 事实上的“运行测试”入口点python ./setup.py test

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

如果要发布构建工件(例如,旨在运行几乎相同的计算机的代码副本),则requests.txt文件是一种快照确切依赖项信息的流行方法,其中“ install_requires”是一种很好的方法捕获最小和最大兼容版本。但是,无论如何目标计算机几乎都是相同的,我强烈建议创建一个完整的python前缀的tarball。这可能很棘手,太详细了,无法在这里找到。检出pip install的{​​{1}}选项,或虚拟化(又名venv)获取销售线索。

回到示例

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

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

--target

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

baz

答案 5 :(得分:1)

为清楚起见,这里是ThorSummoner's答案的三步走,有些简化。它并不能完全满足我的要求(我会在底部进行解释),但是可以。

步骤1:创建目录和<p> <button onclick="myMove()">Click Me</button> </p> <div id ="myAnimation"></div>

setup.py

filepath_to/project_name/ setup.py 中,输入:

setup.py

第2步:将此目录作为软件包安装

在控制台中运行以下代码:

import setuptools

setuptools.setup(name='project_name')

您可能需要使用python -m pip install --editable filepath_to/project_name 来代替python,这取决于安装python的方式。另外,您可以使用python3代替-e

现在,您的目录看起来或多或少像这样。我不知道鸡蛋是什么。

--editable

此文件夹被认为是python软件包,即使您在计算机上其他任何地方编写脚本,也可以从此父目录中的文件导入。

第3步。从上方导入

假设您制作了两个文件,一个在项目的主目录中,另一个在子目录中。看起来像这样:

filepath_to/project_name/
    setup.py
    test_3.egg-info/
        dependency_links.txt
        PKG-INFO
        SOURCES.txt
        top_level.txt

现在,如果filepath_to/project_name/ top_level_file.py subdirectory/ subfile.py setup.py | test_3.egg-info/ |----- Ignore these guys ... | 看起来像这样:

top_level_file.py

然后,我可以从x = 1 或实际上在计算机上其他任何位置的任何其他文件导入它。

subfile.py

这与我寻找的东西不同:我希望python有一种单行方式可以从上面的文件中导入。取而代之的是,我必须将脚本视为一个模块,进行一堆样板工作,并在全局安装该脚本,以便整个python安装都可以访问它。太过分了。如果有人采用的方法比不涉及上述过程或# subfile.py OR some_other_python_file_somewhere_else.py import random # This is a standard package that can be imported anywhere. import top_level_file # Now, top_level_file.py works similarly. print(top_level_file.x) 恶作剧的方法简单,请告诉我。

答案 6 :(得分:1)

@alex-martellipathlib 的完美答案:

import pathlib
import sys

_parentdir = pathlib.Path(__file__).parent.parent.resolve()
sys.path.insert(0, str(_parentdir))

import module_in_parent_dir

sys.path.remove(str(_parentdir))

答案 7 :(得分:0)

运行导入 python /myprogram/submodule/mymodule.py/myprogram/mainmodule.py,例如通过

from mainmodule import *

在 Linux 上(例如,在 python Docker image 中),我必须将程序根目录添加到 PYTHONPATH

export PYTHONPATH=/myprogram

答案 8 :(得分:-7)

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