星球球友提问:
请问下,import父目录的包是应该用怎样的方式,查询了许多资料也失败了,求解答
字符老师回答:
有朋友遇到在python文件中使用相对路径去import某一个模块,如图1所示,但是执行的时候却报错No module named 'settings'。
图1
报错的意思很明显,找不到引用的模块。检查来检查去,引用的相对路径是对的呀,可是为什么找不到settings这个文件呢。
其实引用并没有错,错在执行的路径上,如果执行时所在的路径是test.py的目录下,那么执行是可以成功的,但是如果不在这个路径下,就会找不到setting这个模块。
这是为什么呢?
关键在于sys.path.append('..') 的'..'。(这段内容都以图1的例子讲解)
'..'表示引用当前目录的上一层目录,请注意这个当前目录的意思,当前目录是指你执行python test.py这个命令时所在的目录,比如你如果在app这个目录下执行,那当前目录就为app这个目录,此时import就能正常进行;如果你是在sample目录下执行python app/test.py 那么当前路径就是sample目录,'..'引入的就是sample的上层目录,那么在sample的上一层就找不到settings这个文件。这就是相对路径。
那这里怎么规避这个问题呢?使用绝对路径 。但是绝对路径并不是手动写入完整路径的字符串,比如'C://python/sample'。如果这样写,当你把你的代码文件夹拷到其他路径,依然会出错。
这里需要用的是动态的绝对路径。根据当前文件实时获取绝对路径,给大家介绍两个方法:
os.path.abspath(file) # 获取当前文件的完整绝对路径 __file__是当前文件的相对路径的文件名
os.path.dirname('文件名/文件夹名') # 获取文件/文件夹所在的目录
知道了上面的用法,我们稍加修改,编程图2的样子,再来运行,不管你在什么路径下执行,都可以得到正确的结果
图2
图2中,我们使用了os.path.dirname(os.path.dirname(os.path.abspath(file)))方法通过了三次处理来获取test.py的上一层目录。我们来分析一下为什么要经过这三次处理
- 第一步:os.path.abspath(file) 获得的是test.py所在的绝对路径'绝对路径/sample/app/test.py'
- 第二步:等效于 os.path.dirname('绝对路径/sample/app/test.py'),得到的是test.py所在的目录 '绝对路径/sample/app'
- 第三步:等效于 os.path.dirname('绝对路径/sample/app'),得到的是app所在的路径'/绝对路径/sample'
所以此时已经把sample的绝对路径加到环境变量中,就可以找到settings.py文件了。
这样的用法在我们的各种框架中也会遇到,比如django项目里,settings.py的BASE_DIR使用的就是这种或者类似的方法。有兴趣的同学可以去django的settings.py文件中查看验证一下。