python中函数调用之路径问题
- 1.导入同级模块
- 2.导入下级模块
- 3.导入上级模块
- 4.导入隔壁文件夹下的模块
- 5.常见错误及import原理
- 6. `python包`内相对导入:向上导航父目录,再向下导入子目录
- 6.1 如果存在多级目录,是否每个文件夹下都要有一个__init__.py文件
- 6.2 自定义的python模块,存在多级目录,如何实现不同级别目录文件之间函数调用
- 6.3 如果函数调用时,跨越的级别不是上级目录,而是很多级别的目录呢
- 6.4 如果是5级父目录呢
- 6.5 向上导航到父目录,再向下导航到多级子目录
- 6.6 向上两级,向下五级
- 6.7 如何添加调用函数的目录到 Python 路径
- 当当前python文件调用另一个python文件的函数时,以什么路径为当前python解释器的路径
- 6.8 当一个python文件调用另一个python文件的函数时,另一个python文件中的导入自定义包的路径是什么
- 6.9 上述例子中,如何使用绝对导入
- 6.10 `..` 表示什么
- 6.11 错误问题
假设有如下目录结构:
-- 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 包的特殊文件,它的作用有以下几个方面:
-
标识目录为 Python 包: 当一个目录包含
__init__.py
文件时,Python 将把该目录视为一个包。这使得您可以通过包的名字来组织和导入模块。 -
包级别的初始化代码: 您可以在
__init__.py
中放置包级别的初始化代码,这些代码在包第一次被导入时会执行。这通常用于设置包的全局变量、导入子模块、执行初始化任务等。 -
导出内容: 您可以在
__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
时访问 module1
和 module2
,就好像它们是 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
中的函数。
-
在
sub_module1.py
中,使用相对导入导入module1.py
。from .. import module1 # 使用两个点表示父级目录
-
现在,您可以在
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 路径,您可以使用以下方法之一:
- 使用
sys.path
修改Python路径:在代码中,您可以使用sys.path.append()
方法将目录添加到 Python 路径。例如:
import sys
sys.path.append('/path/to/your/directory')
确保将 /path/to/your/directory
替换为实际目录的路径。这将使 Python 解释器能够在指定的目录中查找模块。
- 使用环境变量
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 上述例子中,如何使用绝对导入
在上述示例中,如果您希望使用绝对导入而不是相对导入,您可以按照以下方式操作:
-
确保
my_project
目录(包含main.py
和my_module
目录)在 Python 路径中,或者将其添加到 Python 路径中。 -
使用绝对导入导入其他自定义包,以确保它们能够从任何位置正确导入。
示例代码如下:
# 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
,但似乎这个相对导入尝试跳出了顶级包。
为了解决这个问题,您可以考虑以下几种方法:
-
绝对导入:使用绝对导入,直接导入目标模块。这将绕过相对导入的问题,但需要提供完整的模块路径。
from model.point2skeleton.src.SkelPointNet import SkelPointNet
-
重组项目结构:考虑将项目结构重新组织,以确保您的模块在同一包内或其下级包内。这样,您可以使用相对导入。
-
将模块移动到正确的位置:如果
SkelPointNet
应该属于model.point2skeleton.src
包,确保它位于正确的目录中。 -
修改
sys.path
:这不是最佳做法,但您可以通过将模块所在的目录添加到sys.path
中来使相对导入起作用。这通常不推荐使用,因为它可能会导致不一致的导入行为。
请根据您的项目结构和需求选择适合的解决方法。最常见的方法是使用绝对导入或重新组织项目结构,以确保模块在正确的位置。