前言:
在python中其实import上层模块是不正规的写法,但是偶尔测试会用到。虽然我不提倡,但是说一下吧。而且这方法还有个很实用的地方哦!希望大家能看到最后。
网上有些教程说 from .. import xxx 就能引入上层,亲测报错,大家不用试了,本文也有测试哦。
还有些教程说 “把要import的包放到python的安装目录下(类似c:/python27)就能直接import”。这可以实现的,但问题是,系统自带的和你自定义的混在一起,以后要修改很容易会改错系统文件,如果命名不好(例如,用一些什么requests.py之类的命名)有可能import会有未知错误。简单说,混乱!
我不断查阅资料和专研后,想到一个神句
#-*-coding:utf-8-*-
import sys
sys.path.append('../')
实例:
1、基础
这是我的文件目录树,__init__.py是必须的,要告诉python这目录是一个模块,里面可以什么都没有。
#a.py
def show_a():
print('Hi,I import a!')
#/level1/b.py
def show_b():
print('Hi,i import b!')
#\level1\level2\c.by
def show_c():
print('Hi,I import c!')
#\level1\level2\level3\d.by
def show_d():
print('Hi,I import d!')
main.py是主函数。我们运行它来测试。先来简单温习下基础吧。引用同级目录和子目录的方法。
#-*-coding:utf-8-*-
#同级目录
from b import show_b
#下级目录
from level2.c import show_c
#下下级目录
from level2.level3.d import show_d
def tx():
#show_a()
show_b()
show_c()
show_d()
if __name__ == '__main__':
tx()
输出结果是:
Hi,i import b!
Hi,I import c!
Hi,I import d!
2、上级目录
好了我们想import上级目录的show_a。
2-1 假方法
大家可以试试网上说的from ..a import show_a【这是错的!不想看就直接跳到2-2吧。】
#-*-coding:utf-8-*-
#同级目录
from b import show_b
#下级目录
from level2.c import show_c
#下下级目录
from level2.level3.d import show_d
from ..a import show_a
def tx():
show_a()
show_b()
show_c()
show_d()
if __name__ == '__main__':
tx()
会在 from ..a import show_a报错:
builtins.ValueError: attempted relative import beyond top-level package
那是因为编译器把我们的运行目录作为 根节点 了。加载模块的时候只加载了系统模块(例如c:\python27)和 本目录下有__init__ 文件夹的模块。
2-2 真方法
研究出来的真方法是——在文件头加入
import sys
sys.path.append('../')
然后直接from xxx import xxx就好。例如我们的:
#-*-coding:utf-8-*-
import sys
sys.path.append('../')
#上级目录
from a import show_a
#同级目录
from b import show_b
#下级目录
from level2.c import show_c
#下下级目录
from level2.level3.d import show_d
#from ..a import show_a
def tx():
show_a()
show_b()
show_c()
show_d()
if __name__ == '__main__':
tx()
运行结果是:
Hi,I import a!
Hi,i import b!
Hi,I import c!
Hi,I import d!
往下说之前先解答下大家问题吧。
1、有人会问“你这不是改了运行路径了吗?我是要在level2下面运行啊!怎么跑到上层了?”
答:其实sys.path是搜索模块的路径。默认由系统模块、本目录下有__init__文件夹模块组成。新加的“神句”是“添加上层目录作为本程序模块之一”的意思。注意这是临时的,其他程序运行并不能使用这模块。
2、“为什么是from a而不是from ..a?不是在上级目录吗?”
答:对,是在上层目录,但是上层目录已经作为类似系统模块的存在了。所以就像大家平时用的from datetime import datetime一样调用就可以了。
3*、最优化
以上方法就足够测试用了。但是,热爱测试的小伙伴们一定会发现这有个BUG。在main.py所在的文件夹运行main.py是正常的。但是在其他目录直接用python运行main.py会发现from a import show_a会提示“找不到模块a”。
例如我的这测试文件夹是桌面的tree。我直接打开cmd输入
C:\Users\Administrator\Desktop>python C:\Users\Administrator\Desktop\tree\level1\main.py
就会报错。
为什么呢?
因为我们添加的是(当前目录的)上级目录 到path里面。直接运行就变成了添加的是C:\Users\Administrator进去了。
因此,我们需要添加(运行目录的)上级目录到path里面,即添加的应该是相对的绝对路径。有点难懂对吧?意思就是“添加的是绝对路径,但必须根据实际运行路径添加”。
最后贴上 真·神句!!!(笑)并测试。
【感谢那些看到最后的小伙伴,转载记得标明出处哦。】
import sys,os
sys.path.append(os.getcwd()+'/../')
实测:
#-*-coding:utf-8-*-
import sys,os
sys.path.append(os.getcwd()+'/../')
#上级目录
from a import show_a
#同级目录
from b import show_b
#下级目录
from level2.c import show_c
#下下级目录
from level2.level3.d import show_d
def tx():
show_a()
show_b()
show_c()
show_d()
if __name__ == '__main__':
tx()
直接cmd运行结果是:
C:\Users\Administrator>python C:\Users\Administrator\Desktop\tree\level1\main.py
Hi,I import a!
Hi,i import b!
Hi,I import c!
Hi,I import d!
附上测试代码:
GIT : https://gitee.com/kid0/tree.git
百度云 : https://pan.baidu.com/s/1zaS0jjYzjD0X3ZOmPafRsg
————————————————————————————————
附录
2018年7月11日
之前代码原本是\\的,现在修正为/。
import sys
sys.path.append(sys.path[0]+'\\..\\')
这是因为‘\\’(即\)在linux的路径下无法被识别。
在windows下,C:\ 或 C:/ 都能轻松访问到C盘。
在linux下, cd \root 是无法访问root文件夹的,只有 cd /root 才可以。
这是因为windows对路径的解释会把\自动转换成/,而linux不转换。
2018年7月17日
再更新一个版本。
之前神句是:
import sys
sys.path.append(sys.path[0]+'/../')
现在改成:
import sys,os
sys.path.append(os.getcwd()+'/../')
直接运行结果没差异的。但是在打包成exe文件后,这就不同了。sys.path[0]会成了打包好库的路径,os.getcwd()才是运行路径(也就是exe的所在路径)。如何打包成exe文件以后博客说。现在为了严谨,还是修正下。不然打包好的exe会报错。
[WinError 3] 系统找不到指定的路径。: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\
\_MEI37602\\base_library.zip\\a'