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

我想从当前目录上方目录中的文件中的类继承。

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

I want to inherit from a class in a file that lies in a directory above the current one.

Is it possible to relatively import that file?


回答 0

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处理绝对/相对进口。

from ..subpkg2 import mod

Per the Python docs: When inside a package hierarchy, use two dots, as the import statement doc says:

When specifying what module to import you do not have to specify the absolute name of the module. When a module or package is contained within another package it is possible to make a relative import within the same top package without having to mention the package name. By using leading dots in the specified module or package after from you can specify how high to traverse up the current package hierarchy without specifying exact names. One leading dot means the current package where the module making the import exists. Two dots means up one package level. Three dots is up two levels, etc. So if you execute from . import mod from a module in the pkg package then you will end up importing pkg.mod. If you execute from ..subpkg2 import mod from within pkg.subpkg1 you will import pkg.subpkg2.mod. The specification for relative imports is contained within PEP 328.

PEP 328 deals with absolute/relative imports.


回答 1

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

回答 2

如果您可以保证他提到的软件包层次结构, @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

@gimel’s answer is correct if you can guarantee the package hierarchy he mentions. If you can’t — if your real need is as you expressed it, exclusively tied to directories and without any necessary relationship to packaging — then you need to work on __file__ to find out the parent directory (a couple of os.path.dirname calls will do;-), then (if that directory is not already on sys.path) prepend temporarily insert said dir at the very start of sys.path, __import__, remove said dir again — messy work indeed, but, “when you must, you must” (and Pyhon strives to never stop the programmer from doing what must be done — just like the ISO C standard says in the “Spirit of C” section in its preface!-).

Here is an example that may work for you:

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

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

from .. import module

Import module from a directory which is exactly one level above the current directory:

from .. import module

回答 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

我的首选是创建与的兄弟姐妹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

How to load a module that is a directory up

preface: I did a substantial rewrite of a previous answer with the hopes of helping ease people into python’s ecosystem, and hopefully give everyone the best change of success with python’s import system.

This will cover relative imports within a package, which I think is the most probable case to OP’s question.

Python is a modular system

This is why we write import foo to load a module “foo” from the root namespace, instead of writing:

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 isn’t coupled to a file-system

This is why we can embed python in environment where there isn’t a defacto filesystem without providing a virtual one, such as Jython.

Being decoupled from a filesystem lets imports be flexible, this design allows for things like imports from archive/zip files, import singletons, bytecode caching, cffi extensions, even remote code definition loading.

So if imports are not coupled to a filesystem what does “one directory up” mean? We have to pick out some heuristics but we can do that, for example when working within a package, some heuristics have already been defined that makes relative imports like .foo and ..foo work within the same package. Cool!

If you sincerely want to couple your source code loading patterns to a filesystem, you can do that. You’ll have to choose your own heuristics, and use some kind of importing machinery, I recommend importlib

Python’s importlib example looks something like so:

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

Packaging

There is a great example project available officially here: https://github.com/pypa/sampleproject

A python package is a collection of information about your source code, that can inform other tools how to copy your source code to other computers, and how to integrate your source code into that system’s path so that import foo works for other computers (regardless of interpreter, host operating system, etc)

Directory Structure

Lets have a package name foo, in some directory (preferably an empty directory).

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

My preference is to create as sibling to foo.py, because it makes writing the setup.py file simpler, however you can write configuration to change/redirect everything setuptools does by default if you like; for example putting foo.py under a “src/” directory is somewhat popular, not covered here.

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/

“editable” aka -e will yet-again redirect the importing machinery to load the source files in this directory, instead copying the current exact files to the installing-environment’s library. This can also cause behavioral differences on a developer’s machine, be sure to test your code! There are tools other than pip, however I’d recommend pip be the introductory one :)

I also like to make foo a “package” (a directory containing __init__.py) instead of a module (a single “.py” file), both “packages” and “modules” can be loaded into the root namespace, modules allow for nested namespaces, which is helpful if we want to have a “relative one directory up” import.

some_directory/
    foo/
        __init__.py
    setup.py

.

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

import setuptools

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

I also like to make a foo/__main__.py, this allows python to execute the package as a module, eg python3 -m foo will execute foo/__main__.py as __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',
        ]
    },
)

Lets flesh this out with some more modules: Basically, you can have a directory structure like so:

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 conventionally holds metadata information about the source code within, such as:

  • what dependencies are needed to install named “install_requires”
  • what name should be used for package management (install/uninstall “name”), I suggest this match your primary python package name in our case foo, though substituting underscores for hyphens is popular
  • licensing information
  • maturity tags (alpha/beta/etc),
  • audience tags (for developers, for machine learning, etc),
  • single-page documentation content (like a README),
  • shell names (names you type at user shell like bash, or names you find in a graphical user shell like a start menu),
  • a list of python modules this package will install (and uninstall)
  • a defacto “run tests” entry point python ./setup.py test

Its very expansive, it can even compile c extensions on the fly if a source module is being installed on a development machine. For a every-day example I recommend the PYPA Sample Repository’s setup.py

If you are releasing a build artifact, eg a copy of the code that is meant to run nearly identical computers, a requirements.txt file is a popular way to snapshot exact dependency information, where “install_requires” is a good way to capture minimum and maximum compatible versions. However, given that the target machines are nearly identical anyway, I highly recommend creating a tarball of an entire python prefix. This can be tricky, too detailed to get into here. Check out pip install‘s --target option, or virtualenv aka venv for leads.

back to the example

how to import a file one directory up:

From foo/spam/eggs.py, if we wanted code from foo/baz we could ask for it by its absolute namespace:

import foo.baz

If we wanted to reserve capability to move eggs.py into some other directory in the future with some other relative baz implementation, we could use a relative import like:

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

Python is a modular system

Python doesn’t rely on a file system

To load python code reliably, have that code in a module, and that module installed in python’s library.

Installed modules can always be loaded from the top level namespace with import <name>


There is a great sample project available officially here: https://github.com/pypa/sampleproject

Basically, you can have a directory structure like so:

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.

.

Be sure to declare your setuptools.setup() in setup.py,

official example: https://github.com/pypa/sampleproject/blob/master/setup.py

In our case we probably want to export bar.py and foo/__init__.py, my brief example:

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
)

.

Now we can install our module into the python library; with pip, you can install the_foo_project into your python library in edit mode, so we can work on it in real time

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

.

Now from any python context, we can load our shared py_modules and packages

foo_script.py

#!/usr/bin/env python3

import bar
import foo

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

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。