python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > python相对路径导入

python中相对路径导入的正确用法及错误避免方法

作者:脊柱蛀虫

这篇文章主要为大家详细介绍了python中相对路径导入的正确用法及报错ImportError: attempted relative import with no known parent package的相关解决方法,有需要的小伙伴可以了解下

前言

相对导入只适合包内模块去使用!!!

一个 .py 文件一旦使用相对导入,则直接运行该文件一定会报错:“ImportError: attempted relative import with no known parent package”

正确的使用方法是:

包内的模块之间使用相对导入,包外的模块通过绝对路径导入去调用这个包中的模块。

【包内相对导入,包外绝对导入】

示例:

假设现有如下文件结构,main.py 与 package 在同一级目录。package 是一个文件夹(包),其中包含了模块 module1.py 和 module2.py 以及包的初始化文件__init__.py。即,main.py在包外,module1.py在包内。

main.py
package/
├── __init__.py
├── module1.py
└── module2.py

 包内相对导入:

现在假设 package 内的模块 module1 相对导入了同级目录的模块 module2 的函数 func2 。

module1.py :

# module1.py
from .module2 import func2

包外间接调用:

main.py :

# main.py
from package.module1 import func2
func2()

module2.py: 

# module2.py
def func2():
    print("func2")

则运行 main.py 的输出结果是:

func2 

如果你不知道什么是文件夹和包的区别,不知道什么是相对导入和绝对导入,以下是一些补充信息。

1. 基础概念辨析:模块、包、文件夹的区别

2. 绝对路径和相对路径(Absolute & Relative)

2.1 使用方法

假设有一个包结构如下:

package/
├── __init__.py
├── module1.py
└── subpackage/
    ├── __init__.py
    └── module2.py

module1中绝对导入 module2

# module1.py
from package.subpackage import module2

module2.func2()

module2 中绝对导入 module1

# module2.py
from package import module1

module1.func1()

module1中相对导入 module2

# module1.py
from .subpackage import module2

module2.func2()

module2中相对导入 module1

# module2.py
from .. import module1

module1.func1()

2.2 使用场景

绝对导入的使用场景

相对导入的使用场景

2.3 注意事项

相对导入的限制

绝对导入的优点

总是实在不行就用绝对导入,只要你的文件位置不会变来变去,包不出错的。

3. 基础的 import 语法

3.1 导入方法1:导入整个模块

先导入整个模块,再通过模块名访问指定对象。 模块中的所有对象(函数、类、变量等)都可以通过 模块名.对象名 的方式访问。例如:

import 模块名
模块名.函数名()

优点:可以清楚地知道对象来自哪个模块 & 不会污染当前命名空间。

缺点: 前缀冗长。

3.2 导入方法2:导入模块中的所有对象

一口气导入模块中的所有对象(函数、类、变量等),模块中的所有对象都可以使用原本的名字直接调用:

from 模块名 import *
函数名()

优点:调用简洁。

缺点:不清楚哪些对象被导入了 & 可能命名冲突。

3.3 导入方法3:导入模块中的指定对象

将指定的对象导入到当前命名空间中,可以直接使用对象名调用,而不需要加上模块名作为前缀。 

from 模块名 import 函数名, 对象2, ...
函数名()

优点:调用简洁。

缺点是:可能命名冲突。

3.4 导入方法4:别名导入

为模块设置一个别名,使用别名来访问模块中的对象。

为导入的对象设置别名,下面以函数对象为例。

import 模块名 as 模块别名
from 模块名 import 函数名 as 函数别名
模块别名.函数名()
函数别名()

这种方法主要用于解决名字过长和命名冲突问题。

4. 包的导入

4.1 导入包中的模块(当前文件与包在同一级目录)

如果模块位于一个包中,可以使用点号(.)来指定路径。

示例: 假设当前文件结构如下:

main.py

package/
├── __init__.py
├── module1.py
└── subpackage/
    ├── __init__.py
    └── module2.py

( __init__.py 文件不可以缺省!!不然你之后运行 main.py 会报错,例如:AttributeError: module 'package' has no attribute 'module1' )

随后,在 main.py 中,可以这样导入模块并使用(假设你在 module1 和 module2 中分别实现了函数 func1 和 func2 ):

# main.py
import package.module1
import package.subpackage.module2

package.module1.func1()
package.subpackage.module2.func2()

这样很麻烦对不对?前缀死长死长的。 

4.2 导入包中的对象

可以使用绝对路径直接导入包中的对象:

# main.py
from package.module1 import func1
from package.subpackage.module2 import func2
func1()
func2()

但是这样导入,如果包的层次很多怎么办,那导入语句就会很长?所以接下来讲讲 __init__.py 怎么用,这才是包的作用!【本质其实有点像是超链接】搞完后面的操作你就可以像下面这样导入并调用包里的函数了:

# main.py
from package import func1, func2
func1()
func2()

只需要在两个 __init__.py 文件中分别增加以下内容就可以了!

# package/__init__.py
from .module1 import func1
# package/subpackage/__init__.py
from .module2 import func2

如果你直接执行这些__init__.py文件,则会报错:ImportError: attempted relative import with no known parent package  这是正常的。

4.3 相对导入(仅适用于包内导入)

在包内部的模块之间可以使用相对导入。

示例:module1.py 中导入 subpackage/module2.py 中的 func2

from .subpackage.module2 import func2

注意:

5. 其它一些你可能需要的信息

5.1 命名冲突

如果导入的对象与当前命名空间中的对象同名,会导致冲突。可以通过别名解决。

示例:

from math import sqrt
from mymodule import sqrt as my_sqrt

print(sqrt(16))    # 使用 math 模块中的 sqrt
print(my_sqrt(16)) # 使用 mymodule 模块中的 sqrt

5.2 模块查找路径

使用 import 语句导入模块时,python如何识别导入的模块时哪一个?

Python 会按照以下顺序查找模块:

如果模块不在这些路径中,可以通过以下方式解决:

将模块目录添加到 sys.path

import sys
sys.path.append('/path/to/module/directory')

修改 PYTHONPATH 环境变量。

5.3 循环依赖

如果两个模块相互导入对方,可能会导致循环依赖问题。尽量避免这种情况,或者通过调整模块结构来解决。

ps:我之前没搞明白包和模块啊这些东西的概念,乱用一通,导致项目老是报错,特别是乱七八糟的导入引用,VSCode打开的文件夹层级变一下也会导致原本正常的程序报错。。。一开始我直接在浏览器搜,看了几篇文章感觉讲得乱七八糟的看不懂,最后还是求助KIMI老师,然后自己实践了一遍,终于是大概明白之前为啥老是报错了(就文中提到的ImportError: attempted relative import with no known parent packageAttributeError: module 'package' has no attribute 'module1' )。

到此这篇关于python中相对路径导入的正确用法及错误避免方法的文章就介绍到这了,更多相关python相对路径导入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文