Python基础 - 本地模块的相对导入/引用

如果把绝对和相对导入都放在一个文章写,会显得过于冗长,所以我分开来写,我将会延续上一篇文章Python基础 - 本地模块的绝对导入的文件树和示例来讲相对引用,以及常见的一些问题。没看上一篇的小伙伴可以先去把上一篇看完,这样更容易理解。

文件树如下:

Import_Test
  |--dir1
      |--d11.py
      |--d12.py        
  |--dir2
      |--d21.py
      |--d22.py
  |--test.py     

在讲解之前,我们需要明确的几点是,相对导入中"." ".."都是什么意思?.表示的是当前目录,也就是目前文件所在的目录,..就是当前文件所在目录的父目录。对于test.py来说,.代表的是Import_Test文件,对d11.py来说,.代表dir1,..代表Import_Test

示例1:使用相对引用,引入入口文件的同级目录文件dir1 (会报错)

# test.py ----------------------------
# 绝对引入:from dir1.d11 import d11_f
from .dir1.d11 import d11_f
 
def test_f():
    print("test")
 
if __name__ == '__main__':
    test_f()
    d11_f()
 
# 运行结果报错如下:
(base) zhangyujun@118:~/Wmq/Import_Test$ python test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    from .dir1.d11 import d11_f
ImportError: attempted relative import with no known parent package

感觉第一行的绝对引用没有问题,.表示的是当前test.py的父目录Import_Test,然后它下面的dir1。那为什么会有"no known parent package"错误呢?是这样的,当执行test.py时首先加入sys.path的是该文件所在目录:/home/zhangyujun/Wmq/Import_Test,但由于目录无法通过其自身找到同级目录,只能找到其子目录,所以会报错。所以不加那个"."即可。

示例2:test.py没变,引入的子模块dir1.d11同时引入同级模块dir1.d12

# test.py ----------------------------
from dir1.d11 import d11_f
 
def test_f():
    print("test")
 
if __name__ == '__main__':
    test_f()
    d11_f()
 
# dir1/d11.py ------------------------
# 绝对引用:from dir1.d12 import d12_f
from .d12 import d12_f
 
def d11_f():  
  print("d11_f")
  d12_f()
 
def d11_f():  
  print("d11_f")
  d12_f()
 
# dir1/d12.py ------------------------
def d12_f():  
  print("d12_f")
 
# 运行结果如下:
(base)@118:~/Wmq/Import_Test$ python test.py
test
d11_f
d12_f

对于第二个from,相对于绝对引用:from dir1.d12 import d12_f。在相对引用中改成了from .d12 import d12_f。很好理解,.表示的是d12所在的目录dir1,而dir1能够通过根目录/home/zhangyujun/Wmq/Import_Test找到,所以就可以使用.引入d12.

示例3:test.py没变,引入的子模块dir1.d11同时引入跨文件夹模块dir2.d21

# dir1/d11.py ------------------------
# 绝对引用:from dir2.d21 import d21_f
from ..dir2.d21 import d21_f 
def d11_f():
  print("d11_f")
  d21_f()
 
# dir2/d21.py ------------------------
def d21_f():
  print("d21_f")
 
# 运行结果报错如下:
ValueError: attempted relative import beyond top-level package

 这个报错跟示例1中的报错原因相同,dir1下的d11文件中,里面出现了..,也就是dir1的父目录/Import_Test,但由于目录无法通过其自身找到同级目录,只能找到其子目录,所以会报错。

示例4:如果不运行test.py了,只运行dir1/d11.py, 其他任何引用不变,结果如下:

# dir1/d11.py -------------------
from dir2.d21 import d21_f
 
def d11_f():
  print("d11_f")
  d21_f()
 
if __name__ == '__main__':
  d11_f()
 
# 运行结果报错,如下:
(base) zhangyujun@118:~/Wmq/Import_Test/dir1$ python d11.py
Traceback (most recent call last):
  File "d11.py", line 1, in <module>
    from dir2.d21 import d21_f
ModuleNotFoundError: No module named 'dir2'

根据上一篇文章,解决这种问题的方法就是在sys.path路径中加入根路径,即

# dir1/d11.py -------------------
import sys
sys.path.append("/home/zhangyujun/Wmq/Import_Test")

但这是绝对引用,如果想要改成相对引用会怎么办呢?如下,添加"..",当前文件所在目录的父目录,即:"/home/zhangyujun/Wmq/Import_Test"

# dir1/d11.py -------------------
import sys
sys.path.append("..")

其实整体下来,我还是比较推荐使用绝对引用来进行模块引入的,会避免很多不必要的错误。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值