我相信你肯定遇到过这样的报错

Traceback (most recent call last):
File "main.py", line 549, in <module>
os.chdir(os.path.dirname(__file__))
FileNotFoundError: [Errno 2] No such file or directory: ''

这还要从python的路径问题说起
首先我们了解一下几个重要的概念

这里的 Desktop 指的是运行路径
寻找python 脚本的方式是相对路径寻找
__file__ 变量值为 path_test/test.py
知道这些我下面具体说 运行路径不同 会导致的问题

运行路径不同导致的问题

举一个简单的例子

在这个项目中有一个 1.txt 里面包含 Hello world字符串, 这段程序就是简单的寻找然后并输出,正常是可以输出的像这样在 sublime 中运行,得到结果:

而我们以另一种方式运行:

这样就会提示找不到这个文件,为什么会有这样的问题?
这里出现这种状况的原因主要是因为运行路径不同,而寻找相对路径的 1.txt 文件也就不同。
第一种寻找的 1.txt 真正路径是在 /home/wshuo/Desktop/path_test/1.txt
而第二种寻找的 1.txt 的真正路径是在 /home/wshuo/Desktop/1.txt 这当然会找不到了
这是因为 sublime 运行脚本的时候首先会将脚本存在的路径作为运行路径, 而第二种在终端运行的时候,会把当前所在的路径作为运行路径(我所在的是 Desktop)
下面我简单写一个例子来证明以上两点说法:


os.getcwd() 这个路径可以获取到当前的路径(也就是程序运行的路径)

运行路径不同找不到文件的解决方案

  1. 第一种你可以把 修改 txt 文本文件改为绝对路径,显然这不是好的解决办法,因为代码不一定存放在什么地方,写成绝对路径寻找txt 文件绝对是很傻的解决方案
  2. 更改运行的路径, 无论在什么路径运行都更改到项目路径下运行,这样无论 整个项目存放在什么地方都可以找到 txt 文件了

那么如何更改我们的运行路径呢?
我猜大部分都是这样写的

import os

print(__file__)
path = os.path.dirname(__file__)
print(path)
os.chdir(path)
print(os.getcwd()) with open('1.txt') as f:
s = f.read()
print(s)

__file__ 的意思是 寻找这个脚本的路径+这个脚本文件的名字(可以是绝对路径寻找或相对路径寻找)
os.path.dirname 这个函数可以取出文件所在的路径
os.chardir 更改运行路径,下面我再使用这两种方式运行这段代码
所以上面代码的作用就可以解决 无论运行路径是否在脚本所在的路径都可以更改为脚本所在的路径


可以看到就算运行路径不在项目路径也不会报错了

更改运行路径导致的其他问题

但是问题真的就解决了吗?
下面我们换一种运行方式来运行
可以看到,更改完的代码进入项目路径运行反而会出错,而我们也可以看到 __file__ 变为了 test.py
这里报错是因为 __file__ 没有路径了完全就是一个文件名字了,所以肯定就获取不到他的父级目录了,而这段代码为什么在 sublime 运行的时候没有报错? 不应该他们运行的路径都是项目路径吗?
我们来看另一种运行方式(可能看到这里你已经懵逼了,但是其实我后面会做一个总结看完总结在看这些一下子就清晰明了了)

可以看到这里我们又没有报错了,因为这里我们寻找这个脚本文件是绝对路径寻找的!
前面我一直再说运行路径 不同导致的问题,这里引入一个新的概念:寻找脚本的方式 绝对路径寻找 和相对路径寻找

python运行方式分类

运行媒介 运行路径 寻找脚本的方式
ide 运行 文件所在路径 绝对路径寻找
双击脚本文件 文件所在路径 绝对路径寻找
cmd 或终端运行 不确定,看当前所在的路径 绝对路径寻找或相对路径寻找

可以看到 在终端或 cmd 中运行脚本的时候是最灵活的了,而我们可以以相对路径寻找和绝对路径寻找运行脚本, 运行路径也可以随着当前所在的路径不同而不同,所以用os.chdir上面修改过的代码可以在

运行路径 寻找脚本的方式
任意 至少有一级父级目录的相对路径寻找或直接的绝对路径寻找

这种条件下运行成功,因为如果进入项目路径下运行的话就必须有至少一层父级路径可以提供,否则获取不到父级路径,也就更改不了运行路径(报错是在获取不到父级目的地方报错)
知道报错原因,你也可以在项目路径这样运行脚本

wshuo@wshuo-Aspire-F5-572G:~/Desktop/path_test$ python3 ../path_test/test.py
Hello world!

这样也不会报错,就是退到上级目录然后在进入项目目录运行,这样就可以获取到文件所在的目录了,但是很傻,我们又不能确定用户会不会在文件所在目录运行这个脚本,更不会确定用户会不会以这样的方式运行脚本

最终的解决办法

  1. 做一个简单的容错处理
import os

try:
os.chdir(os.path.dirname(__file__))
except:
pass with open('1.txt') as f:
s = f.read()
print(s)

这种解决方案肯定包含了所有情况,因为只有当 运行路径为 项目路径时 且python 后面只有 test.py 这个文件名的时候 才会报错,但在这种情况下根本不需要考虑更改运行路径的问题, 因为运行路径已经是 项目路径了,肯定是可以找到 1.txt 文件的

  1. 用 os.path.abspath 处理一下再获取脚本所在路径
import os
os.chdir(os.path.dirname(os.path.abspath(__file__)))
with open('1.txt') as f:
s = f.read()
print(s)

这种解决方案也是不管 __file__ 这个变量是只是一个文件名经过获取绝对路径都可以变成绝对路径+文件名 的形式, 这样再获取脚本所在的路径肯定也不会报错的

关于python路径的问题思考的更多相关文章

  1. Mac Python路径总结

    Mac 下Python 可以多版本的并存,并且Python的目录也有好几个,不过总体来说,Mac 自带的有python 还是比较方便的 Mac 系统自带的又Python ,可能Python版本需要更新 ...

  2. 沉淀,再出发:python爬虫的再次思考

    沉淀,再出发:python爬虫的再次思考 一.前言    之前笔者就写过python爬虫的相关文档,不过当时因为知识所限,理解和掌握的东西都非常的少,并且使用更多的是python2.x的版本的功能,现 ...

  3. Python开发环境Wing IDE设置Python路径详解

    在使用Wing IDE的时候,Python源代码取决于PYTHONPATH(无论是外部或通过内部改变sys.path系统设置),用户需要将路径设置到Wing IDE中. 这个值可以从项目菜单和工具栏的 ...

  4. Spring中统一相同版本的api请求路径的一些思考

    Spring中统一相同版本的api请求路径的一些思考 问题场景 当我们在实际开发中,可能会遇到开发相同同版本的api, 假设相同版本的api请求路径为/v1/functionA,/v1/functio ...

  5. python - 路径处理 和 模块导入

    # -*- coding:utf-8 -*- '''@project: jiaxy@author: Jimmy@file: study_模块导入.py@ide: PyCharm Community E ...

  6. pycharm怎么修改python路径

    今天安装Django的时候遇到了python版本冲突,找不到python路径,所以又重新安装了一个python3.6.5 安装完之后,突然发现自己的pycharm是之前Anaconda的3.5版本,那 ...

  7. python路径写入注册表,导入三方模块win32

    python在安装第三方模块时候,需要将python的路径写入注册表,否则会提示 'python version 3.8-32 required,which was not found in the ...

  8. 查找默认安装的python路径,并输出到 FindPythonPathX_output.txt

    在python程序设计教学中,在汉化IDEL时.为PyCharm项目设置解释器时,经常需要查找python安装路径.对老手来说很简单,但对很多刚开始学习编程的学生来说,则很困难.所以,编写了一个批处理 ...

  9. python 路径操作工具 pathlib,比 os 模块好用太多

    在 python 当中,如果你想控制路径,基本上绕不开 os.path.我希望看完这篇文章以后,熟练使用 python 的你能立刻开始使用 pathlib 模块,一刻也不要耽误. pathlib 相对 ...

  10. Python路径总结

    Windows下文件路径的分隔符是'\'反斜杠,文件路径也是一个字符串,牵扯到'\'在Python字符串中存在转义的情况,就对这个问题做一个探究. Python字符串中要使用'\'时有两种方法: 使用 ...

随机推荐

  1. Kubernetes 监控--Alertmanager

    前面我们学习 Prometheus 的时候了解到 Prometheus 包含一个报警模块,就是我们的 AlertManager,Alertmanager 主要用于接收 Prometheus 发送的告警 ...

  2. Elasticsearch:如何对PDF文件进行搜索

    Elasticsearch 通常用于字符串,数字,日期等数据类型的检索,但是在 HCM.ERP 和电子商务等应用程序中经常存在对办公文档进行搜索的需求.今天的这篇文章中我们来讲一下如何实现 PDF.D ...

  3. 连接FastDFS出现超时问题的解决办法

    1.使用Java语言写的web项目,jeecg框架连接FastDFS,需要修改的信息如下: # WEB-INF/classes/fdfs_client.conf connect_timeout=300 ...

  4. DML添加数据-删除数据-修改数据

    DML添加数据 语法 insert into 表名(列名1,列名2,列名n) values(值1,值2,值n) 列:INSERT INTO day02(id,NAME,age) VALUES(1,&q ...

  5. go使用JWT进行跨域认证最全教学

    JWT前言 JWT是JSON Web Token的缩写.JWT本身没有定义任何技术实现,它只是定义了一种基于Token的会话管理的规则,涵盖Token需要包含的标准内容和Token的生成过程. JWT ...

  6. golang channel底层结构和实现

    一.介绍 Golang 设计模式: 不要通过共享内存来通信,而要通过通信实现内存共享 channel是基于通信顺序模型(communication sequential processes, CSP) ...

  7. SpringBoot课程学习(一)

    @SpringBootTest指定测试的启动类 声明@SpringBootTest @Test注解 @Test 指定测试方法 @Order排序 一:先声明排序模式 @TestMethodOrder(M ...

  8. Linux shell猜数游戏

    题目:猜随机数随机1-100中的一个数字,要求用户猜数字,猜中则退出脚本并告知用户猜测次 数和随机数字,否则要求用户继续猜,并告知当前猜的数字和随机数的关系. #!/bin/bash #猜数游戏 Ra ...

  9. POJ3237 Tree (树链剖分)

    通过打懒标记实现区间取反,和线段树基本操作都差不多. 本题还是一道边权化为点权的问题. 200行巨长代码: 1 #include<cstdio> 2 #include<cstring ...

  10. MQ系列6:消息的消费

    MQ系列1:消息中间件执行原理 MQ系列2:消息中间件的技术选型 MQ系列3:RocketMQ 架构分析 MQ系列4:NameServer 原理解析 MQ系列5:RocketMQ消息的发送模式 在之前 ...