python中函数调用之路径问题

假设有如下目录结构:

-- dir0
  | file1.py
  | file2.py
  | dir3
   | file3.py
  | dir4
   | file4.py

dir0文件夹下有file1.py、file2.py两个文件和dir3、dir4两个子文件夹,dir3中有file3.py文件,dir4中有file4.py文件。

1.导入同级模块

python导入同级模块(在同一个文件夹中的py文件)直接导入即可。

import xxx

例如:在file1.py中想导入file2.py,注意无需加后缀".py":

import file2
# 使用file2中函数时需加上前缀"file2.",即:
# file2.fuction_name()

2.导入下级模块

导入下级目录模块也很容易,需在下级目录中新建一个空白的__init__.py文件再导入:

from dirname import xxx

例如:在file1.py中想导入dir3下的file3.py,首先要在dir3中新建一个空白的__ init __.py文件。

-- dir0
  | file1.py
  | file2.py
  | dir3
   | __init__.py
   | file3.py
  | dir4
   | file4.py

再使用如下语句:

from dir3 import file3

或是:

import dir3.file3

# import dir3.file3 as df3

但使用第二种方式则下文需要一直带着路径dir3书写,较为累赘,建议可以另起一个别名。

3.导入上级模块

要导入上级目录下模块,可以使用sys.path:

import sys 
sys.path.append("..") 
import xxx 

例如:如在file4.py中想import上级目录下的file1.py:

import sys 
sys.path.append("..") 
import file1

sys.path的作用

当使用import语句导入模块时,解释器会搜索当前模块所在目录以及sys.path指定的路径去找需要import的模块,所以这里是直接把上级目录加到了sys.path里。

“…”的含义:等同于linux里的‘…’,表示当前工作目录的上级目录。实际上python中的‘.’也和linux中一致,表示当前目录。

当你导入一个包的时候,实际上是导入了这个包的__ init __.py的文件,所以,如果你在init里面写入了其他的import功能,就等于是在初始化的时候帮忙导入了其他东西。

4.导入隔壁文件夹下的模块

如在file4.py中想引入import在dir3目录下的file3.py。

这其实是前面两个操作的组合,其思路本质上是将上级目录加到sys.path里,再按照对下级目录模块的方式导入。

同样需要被引文件夹也就是dir3下有空的__ init __.py文件。

-- dir
  | file1.py
  | file2.py
  | dir3
   | __init__.py
   | file3.py
  | dir4
   | file4.py

同时也要将上级目录加到sys.path里:

import sys
sys.path.append("..")
from dir3 import file3

5.常见错误及import原理

在使用直接从上级目录引入模块的操作时:

from .. import xxx

经常会报错:

ValueError: attempted relative import beyond top-level package

这是由于相对导入时,文件夹实质上充当的是package,也就是包的角色(比如我们常用的numpy、pandas都是包)。如果python解释器没有认同该文件夹是package,那么这就是一个普通的文件夹,无法实现相对导入。

文件夹作为package需要满足如下两个条件:

文件夹中必须存在有__ init __.py文件,可以为空。

不能作为顶层模块来执行该文件夹中的py文件。

init.py的作用

__init__.py 是 Python 包的特殊文件,它的作用有以下几个方面:

  1. 标识目录为 Python 包: 当一个目录包含 __init__.py 文件时,Python 将把该目录视为一个包。这使得您可以通过包的名字来组织和导入模块。

  2. 包级别的初始化代码: 您可以在 __init__.py 中放置包级别的初始化代码,这些代码在包第一次被导入时会执行。这通常用于设置包的全局变量、导入子模块、执行初始化任务等。

  3. 导出内容: 您可以在 __init__.py 中指定哪些模块、函数、类或变量应该在包级别被导出,以供其他代码导入。这通过在 __init__.py 中使用 from 语句来实现。

例如,假设您有以下目录结构:

my_package/
├── __init__.py
├── module1.py
├── module2.py

__init__.py 中,您可以执行如下操作:

# my_package/__init__.py

# 导入子模块
from . import module1
from . import module2

# 导出模块中的内容
__all__ = ['module1', 'module2']

这将允许其他代码导入 my_package 时访问 module1module2,就好像它们是 my_package 的一部分。

总之,__init__.py 文件用于标识目录为 Python 包,执行包级别的初始化代码,并定义包级别的导出内容。这有助于组织和管理大型 Python 项目中的模块和包。

6. python包内相对导入:向上导航父目录,再向下导入子目录

6.1 如果存在多级目录,是否每个文件夹下都要有一个__init__.py文件

在较新的 Python 版本(Python 3.3 及更高版本),您不必在每个目录下都包含 __init__.py 文件来将其标识为包目录。Python 3.3 引入了隐式的包目录支持,这意味着您只需要在最顶层的包目录中包含 __init__.py 文件,而不需要在每个子目录中都包含。

例如,考虑以下目录结构:

my_package/
├── __init__.py
├── module1.py
├── module2.py
└── subpackage/
    ├── __init__.py
    ├── sub_module1.py
    └── sub_module2.py

在这个示例中,只有最顶层的 my_package 目录中包含 __init__.py 文件,而子目录 subpackage 中也包含了它自己的 __init__.py 文件。

这样的组织结构是有效的,Python 3.3 及更高版本会识别这种方式,无需在每个子目录下都包含 __init__.py 文件。只需确保顶层包目录中包含一个 __init__.py 文件,以及其他你希望导出的模块和子包。

但是,请注意,如果您在使用较旧版本的 Python(例如 Python 2.x),则可能需要在每个子目录下都包含 __init__.py 文件,以便将其识别为包目录。在 Python 2.x 中,隐式包目录支持不适用。

总的来说,随着 Python 版本的更新,通常只需要在顶层包目录中包含 __init__.py 文件,但要根据您的 Python 版本和项目需求来决定是否在子目录中包含 __init__.py 文件。

6.2 自定义的python模块,存在多级目录,如何实现不同级别目录文件之间函数调用

在自定义的 Python 模块中,如果存在多级目录,可以使用相对导入来实现不同级别目录文件之间的函数调用。相对导入允许您引用相对于当前模块的位置的其他模块。以下是如何进行相对导入的方法:

假设您有以下目录结构:

my_project/
├── main.py
├── my_package/
│   ├── __init__.py
│   ├── module1.py
│   └── subpackage/
│       ├── __init__.py
│       └── sub_module1.py

sub_module1.py 中,您想要调用 module1.py 中的函数。

  1. sub_module1.py 中,使用相对导入导入 module1.py

    from .. import module1  # 使用两个点表示父级目录
    
  2. 现在,您可以在 sub_module1.py 中使用 module1.py 中的函数。

    result = module1.some_function()
    

通过这种方式,您可以实现不同级别目录文件之间的函数调用。请注意,相对导入使用 .. 来表示上一级目录,以此类推。

6.3 如果函数调用时,跨越的级别不是上级目录,而是很多级别的目录呢

如果您需要在不同级别的目录之间进行函数调用,而不仅仅是上一级目录,您可以使用更多的 .. 来表示更深层次的父级目录。这是一个示例:

假设您的目录结构如下:

my_project/
├── main.py
├── my_package/
│   ├── __init__.py
│   ├── module1.py
│   └── subpackage/
│       ├── __init__.py
│       ├── sub_module1.py
│       └── sub_subpackage/
│           ├── __init__.py
│           └── sub_sub_module.py

现在,假设您想要从 sub_sub_module.py 调用 module1.py 中的函数。您可以使用相对导入来实现这一点:

# sub_sub_module.py
from ...module1 import some_function  # 使用三个点表示更深的父级目录

result = some_function()

在这个示例中,我们使用了 ... 来表示更深层次的父级目录,以便从 sub_sub_module.py 中导入 module1.py 中的函数。

根据目录的深度,您可以使用相应数量的 .. 来表示父级目录。这使您能够在不同级别的目录之间进行函数调用。

6.4 如果是5级父目录呢

如果您需要在 5 级父目录之间进行函数调用,您可以使用 .....,其中每个点代表一个父级目录。例如,假设您的目录结构如下:

my_project/
├── main.py
├── my_package/
│   ├── __init__.py
│   ├── module1.py
│   └── subpackage/
│       ├── __init__.py
│       ├── sub_module1.py
│       └── sub_subpackage/
│           ├── __init__.py
│           ├── sub_sub_module.py
│           └── sub_sub_subpackage/
│               ├── __init__.py
│               └── sub_sub_sub_module.py

要从 sub_sub_sub_module.py 中调用 module1.py 中的函数,您可以使用 5 个点来表示更深层次的父级目录:

# sub_sub_sub_module.py
from .....module1 import some_function  # 使用五个点表示更深的父级目录

result = some_function()

这样,您可以在 5 级父目录之间进行函数调用。根据目录的深度,您可以使用相应数量的 .. 来表示父级目录。

#############

假设您有以下目录结构,需要从最内层的子目录中调用位于更上级目录的函数:

my_project/
├── main.py
├── my_package/
│   ├── __init__.py
│   ├── module1.py
│   └── subpackage1/
│       ├── __init__.py
│       ├── sub_module1.py
│       └── subpackage2/
│           ├── __init__.py
│           ├── sub_module2.py
│           └── subpackage3/
│               ├── __init__.py
│               └── sub_module3.py

假设您需要从 sub_module3.py 中调用 module1.py 中的函数,您可以使用如下导入语句:

# sub_module3.py
from .... import module1  # 使用四个点表示更高级的父级目录

result = module1.some_function()

在这个示例中,我们使用了四个点 .... 来表示更高级的父级目录,以便从 sub_module3.py 中导入 module1.py 中的函数。

根据目录的深度,您可以使用相应数量的 .. 来表示父级目录。这允许您在不同级别的子目录之间进行函数调用。

6.5 向上导航到父目录,再向下导航到多级子目录

您可以使用相对导入,但在 module1.py 中可能需要向上导航到父目录,然后再向下导航到 sub_sub_sub_module.py

假设您的目录结构如下:

my_project/
├── main.py
├── my_package/
│   ├── __init__.py
│   ├── module1.py
│   └── subpackage1/
│   │   ├── __init__.py
│   │   └── sub_module1.py
│   └── subpackage2/
│       ├── __init__.py
│       └── sub_module2.py
└── sub_sub_subpackage/
    ├── __init__.py
    └── sub_sub_sub_module.py

module1.py 中,您可以使用相对导入向上导航到一级父目录,然后再向下导航到 sub_sub_sub_module.py。例如:

# module1.py
from ..sub_sub_subpackage import sub_sub_sub_module  # 向上导航到一级父目录,然后向下导航到sub_sub_sub_module

result = sub_sub_sub_module.some_function()

在这个示例中,我们使用 .. 向上导航到一级父目录,然后导入 sub_sub_sub_module.py 中的函数。这允许您在 module1.py 中调用 sub_sub_sub_module.py 中的函数。

根据目录的深度,您可以使用相应数量的 .. 来表示父级目录。这使您可以在不同级别的模块中进行函数调用。

########

在给定的目录结构中,如果您需要从 module1.py 中导入 module44.py 中的函数,您可以使用以下相对导入:

# module1.py
from ...package1.package2.package3.package4 import module44

result = module44.some_function()

在这个示例中,我们使用了 4 个 .. 来向上导航到 package1,然后进入 package2/package3/package4,并导入 module44.py 中的函数。

根据目录的深度,您可以使用相应数量的 .. 来表示向上导航,然后添加子目录的名称,以便导航到 4 级子目录中的函数。

6.6 向上两级,向下五级

如果您需要从一个较高级别的目录向下导航到 5 级子目录,可以使用相对导入来实现。以下是一个示例:

假设您的目录结构如下所示:

my_project/
    main.py
    my_package/
    __init__.py
    module1.py
package1/
    __init__.py
    module11.py
    package2/
        __init__.py
        module22.py
        package3/
            __init__.py
            module33.py
            package4/
                __init__.py
                module44.py
                package5/
                    __init__.py
                    module55.py

module1.py 中,要从一级父目录向下导航到 package1/package2/package3/package4/package5 子目录并导入 module55.py 中的函数,您可以使用以下相对导入:

# module1.py
from ...package1.package2.package3.package4.package5 import module55

result = module55.some_function()

在这个示例中,我们使用了 ... 来表示向上导航到一级父目录,然后使用 .package1.package2.package3.package4.package5 来向下导航到 5 级子目录,并导入 module55.py 中的函数。

根据目录的深度,您可以使用适当数量的 .. 来向上导航,然后添加足够多的子目录名称,以便向下导航到 5 级子目录中的函数。

6.7 如何添加调用函数的目录到 Python 路径

要将目录添加到 Python 路径,您可以使用以下方法之一:

  1. 使用 sys.path 修改Python路径:在代码中,您可以使用 sys.path.append() 方法将目录添加到 Python 路径。例如:
import sys
sys.path.append('/path/to/your/directory')

确保将 /path/to/your/directory 替换为实际目录的路径。这将使 Python 解释器能够在指定的目录中查找模块。

  1. 使用环境变量 PYTHONPATH:在您的操作系统中设置 PYTHONPATH 环境变量,以包含您希望添加到 Python 路径的目录。这样,无论从何处运行 Python,它都会考虑 PYTHONPATH 中指定的目录。

在 Unix/Linux 系统中,您可以在 shell 中设置 PYTHONPATH 环境变量,例如:

export PYTHONPATH="/path/to/your/directory"

在 Windows 系统中,您可以使用控制面板或系统属性中的环境变量设置功能来设置 PYTHONPATH

请注意,使用环境变量设置 PYTHONPATH 将影响系统中所有 Python 解释器的行为,而使用 sys.path 只会影响当前运行的 Python 解释器。

一旦您将目录添加到 Python 路径中,您就可以从该目录导入模块并调用其中的函数。

当当前python文件调用另一个python文件的函数时,以什么路径为当前python解释器的路径

当一个Python文件调用另一个Python文件的函数时,Python解释器将以包含当前Python文件的目录(即当前工作目录)作为其路径的一部分。这意味着Python解释器将在当前文件所在的目录中查找要导入的模块。

例如,假设您有以下目录结构:

my_project/
├── main.py
├── my_module/
│   ├── __init__.py
│   └── my_functions.py

如果您在 main.py 中调用 my_functions.py 中的函数,Python解释器将使用 main.py 所在的目录(my_project 目录)作为当前工作目录,并在其中查找要导入的模块。这意味着您可以直接导入 my_functions.py,而不需要额外的路径设置。

# main.py
from my_module import my_functions

# 现在您可以调用 my_functions.py 中的函数
my_functions.some_function()

在这个示例中,my_functions.py 可以直接从 main.py 中导入,因为它们位于同一目录中。

请注意,当前工作目录可能会因不同的执行环境而变化,因此在某些情况下,最好使用绝对路径或相对导入,以确保您的代码能够在不同的环境中正常工作。

6.8 当一个python文件调用另一个python文件的函数时,另一个python文件中的导入自定义包的路径是什么

当一个 Python 文件调用另一个 Python 文件的函数时,另一个 Python 文件中导入自定义包的路径(模块搜索路径)通常是相对于当前运行的 Python 文件的目录。这意味着 Python 解释器将从当前运行的 Python 文件所在的目录开始搜索模块。

例如,假设您有以下目录结构:

my_project/
├── main.py
├── my_module/
│   ├── __init__.py
│   ├── my_functions.py
└── sub_directory/
    ├── sub_module.py

如果您在 main.py 中调用 my_functions.py,然后 my_functions.py 尝试导入其他自定义包,例如 sub_module.py,则导入路径相对于 main.py 的目录来解析。

my_functions.py 中,您可以使用相对导入来导入其他自定义包:

# my_functions.py
from .sub_directory import sub_module

# 现在您可以使用 sub_module 中的函数

在这个示例中,导入路径相对于 my_functions.py,因为它位于同一目录中。但是,这仅适用于相对导入和Python包。如果您直接从命令行运行一个Python文件,Python解释器的当前目录通常是包含该文件的目录。

要避免导入路径问题,您可以使用绝对导入或确保Python解释器的工作目录设置正确。绝对导入需要使用绝对路径,而不是相对路径,以确保模块能够从任何位置正确导入。

6.9 上述例子中,如何使用绝对导入

在上述示例中,如果您希望使用绝对导入而不是相对导入,您可以按照以下方式操作:

  1. 确保 my_project 目录(包含 main.pymy_module 目录)在 Python 路径中,或者将其添加到 Python 路径中。

  2. 使用绝对导入导入其他自定义包,以确保它们能够从任何位置正确导入。

示例代码如下:

# main.py

# 添加 my_project 目录到 Python 路径
import sys
sys.path.append('/path/to/my_project')

# 导入 my_functions.py 中的函数
from my_module import my_functions

# 现在您可以调用 my_functions.py 中的函数
my_functions.some_function()

然后,my_functions.py 中可以使用绝对导入导入其他自定义包:

# my_functions.py

# 导入 sub_module.py 中的函数
from sub_directory import sub_module

# 现在您可以使用 sub_module 中的函数

这里,我们将 my_project 目录添加到 Python 路径,以便从 main.py 中导入 my_functions.py,并使用绝对导入在 my_functions.py 中导入其他自定义包。

请确保将 /path/to/my_project 替换为实际的 my_project 目录的路径。这将确保绝对导入在不同的环境中正常工作。

6.10 .. 表示什么

.. 表示父目录的相对路径。在文件系统中,.. 用于指代一个目录的上一级目录。在 Python 中,.. 可以在相对导入中使用,表示从当前模块向上导航到父目录。

例如,如果您的目录结构如下所示:

my_project/
    main.py
    my_package/
    __init__.py
    module1.py
package1/
    __init__.py
    module11.py
    package2/
        __init__.py
        module22.py
        package3/
            __init__.py
            module33.py
            package4
                __init__.py
                module44.py

module33.py 中,如果您希望从当前目录向上导航到 my_package 目录中的 module1.py,可以使用 ..

# module33.py
from ...my_package import module1

result = module1.some_function()

这里,... 表示向上导航两级,以到达 my_package 目录,然后导入 module1.py 中的函数。

根据目录结构和深度,您可以使用适当数量的 ..,以表示向上导航到父目录。

6.11 错误问题

错误消息 “ValueError: attempted relative import beyond top-level package” 表示您尝试进行超出顶级包的相对导入。Python 相对导入是基于包的结构的,因此需要在包内进行相对导入,而不能跳出包的顶级目录。

在给定的代码中,您尝试从 modelnet40_skeleton.py 文件中相对导入 SkelPointNet,但似乎这个相对导入尝试跳出了顶级包。

为了解决这个问题,您可以考虑以下几种方法:

  1. 绝对导入:使用绝对导入,直接导入目标模块。这将绕过相对导入的问题,但需要提供完整的模块路径。

    from model.point2skeleton.src.SkelPointNet import SkelPointNet
    
  2. 重组项目结构:考虑将项目结构重新组织,以确保您的模块在同一包内或其下级包内。这样,您可以使用相对导入。

  3. 将模块移动到正确的位置:如果 SkelPointNet 应该属于 model.point2skeleton.src 包,确保它位于正确的目录中。

  4. 修改 sys.path:这不是最佳做法,但您可以通过将模块所在的目录添加到 sys.path 中来使相对导入起作用。这通常不推荐使用,因为它可能会导致不一致的导入行为。

请根据您的项目结构和需求选择适合的解决方法。最常见的方法是使用绝对导入或重新组织项目结构,以确保模块在正确的位置。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值