python 一个文件test.py访问另一个文件夹readcsv.py,from import 在windows pycharm 和linux 下open引用打开文件问题全解决

问题:一个文件test.py访问另一个文件夹readcsv.py,同时readcsv.py 打开另一个文件result.csv报找不到result.csv文件
目录结构如下:

learnimport/
  --test/  
        --test.py
  --tools/
    --readcsv.py
    --result.csv

FileNotFoundError: [Errno 2] No such file or directory: ‘result.csv’
详细代码:https://github.com/JasonDu1993/leranimport,可以利用这个代码自己做相关测试

一、 所需先验知识

1、 首先需要了解工作目录(working directory)

工作目录表示运行python文件时使用的目录,有些也称为工作空间(working workspace),但是好像没有这个概念,目前先认为是一个东西吧。
1. 通过os.getcwd()获取的就是该python文件所在的工作空间,为该文件所在目录.[注]:当A调用B时,B中运行这句话得到的工作目录还是A所在目录
2. 通过os.chdir(path_name)传入具体的path_name来修改工作目录,如’/home/jsaon/’,[注]PyCharm中点了Run之后,可以配置运行参数(右上角run键左边下拉Edit Configuration),找到Working directory可以配置工作空间,但不建议这样做,最好还是代码修改。

import os


cwd = os.getcwd()  # 获取该文件工作空间
print('cwd', cwd)
os.chdir(os.path.split(cwd)[0])
cwd_ch = os.getcwd()
print('cwd_ch', cwd_ch)

结果

cwd D:\DeepLearning\workspaces\test\learnimport
cwd_ch D:\DeepLearning\workspaces\test

2、 获取当前文件所在目录、上级目录、上上级目录等

2.1 获取当前文件的完整路径

  1. __file__ 获取该文件绝对路径,含后缀。
    会根据代码的工作目录不同呈现不同的风格,如果文件和工作目录一致(即该文件在工作目录里),路径符合linux风格’/’。不一致时,获取的路径符合系统,win下为’\’,linux下为’/’。我认为该变量很神奇,好像和PEP(Python Enhancement Proposals)有关系。
  2. 通过os.path.abspath(__file__)获取该文件绝对路径,含后缀
  3. sys.argv[0]返回值就是(该方法只适合运行该文件,不推荐)。比如这句话放在readcsv.py,然后test.py调用它并运行test.py,得到的结果却是符合linux风格的test.py的完整路径,含后缀。
import os


print('__file__', __file__)
abs_path = os.path.abspath(__file__)  # 获取文件所在目录加该文件名,含后缀
print('abs_path', abs_path)

结果

__file__ D:/DeepLearning/workspaces/test/learnimport/workingdir.py
abs_path D:\DeepLearning\workspaces\test\learnimport\workingdir.py

2.2 获取当前目录

  1. 通过os.path.dirname(__file__) 获取该文件所在目录
  2. 通过先获取完整路径,再分离。
    dir_name = os.path.split(path_name)[0]来获取目录
    module_name = os.path.split(path_name)[1]来获取模块名,但注意含后缀,不想要后缀可以对这个字符串进行module_name.split(‘.’)[0]获取模块名
import os


dir_name = os.path.dirname(__file__)  # 获取文件目录
print('dir_name', dir_name)
dir_split = os.path.split(__file__)  # 分离文件路径
print('dir_split tuple', dir_split)
print('dir_split[0]', dir_split[0])

# dir_abs_name可能更兼容win和linux不同系统下路径
dir_abs_name = os.path.dirname(os.path.abspath(__file__))  # 获取绝对路径下的文件目录
print('dir_abs_name', dir_abs_name)
dir_abs_split = os.path.split(os.path.abspath(__file__))  # 获取绝对路径下的分离文件路径
print('dir_abs_split tuple', dir_abs_split)
print('dir_abs_split[0]', dir_abs_split[0])

结果

dir_name D:/DeepLearning/workspaces/test/learnimport
dir_split tuple ('D:/DeepLearning/workspaces/test/learnimport', 'workingdir.py')
dir_split[0] D:/DeepLearning/workspaces/test/learnimport

dir_abs_name D:\DeepLearning\workspaces\test\learnimport
dir_abs_split tuple ('D:\\DeepLearning\\workspaces\\test\\learnimport', 'workingdir.py')
dir_abs_split[0] D:\DeepLearning\workspaces\test\learnimport

2.3 获取上级目录,上上级目录

  1. 可以通过os.path.dirname(dir_name),传入目录名,返回的就是目录的目录,上上级目录同理
import os


dir_abs_name = os.path.dirname(os.path.abspath(__file__))  # 获取绝对路径下的文件目录
print('dir_abs_name', dir_abs_name)

parent_path = os.path.dirname(dir_abs_name)  # 获得文件的上级目录
print('parent_path', parent_path)
parent2_path = os.path.dirname(parent_path)  # 文件的上上级目录
print('parent2_path', parent2_path)

输出结果:

dir_abs_name D:\DeepLearning\workspaces\test\learnimport
parent_path D:\DeepLearning\workspaces\test
parent2_path D:\DeepLearning\workspaces

3、 模块搜索路径

当我们需要引用别的文件(即一个模块)时,需要了解该模块的搜索路径,通过sys.path进行搜索,该sys.path变量是一个存储路径的List

3.1 添加搜索路径

  1. 主要通过import sys来实现,
    sys.path.append(path_name),path为想要添加的模块搜索目录,该方法是动态添加的,即程序运行时才修改,运行完该文件就不起作用了。注意:当修改了搜索路径后,调用其他文件时,其他文件的搜索路径也会动态改成和运行文件一样的搜索路径,原因:因为python是解释性语言,一句一句的运行,前面运行的结果会影响下一句话,所以即使跨文件该变量也会保留
  2. 也可以设置环境变量PYTHONPATH,不推荐用这种
    1. linux下设置方法为在户主目录下的.profile或.bashrc文件(推荐)末尾加入export PYTHONPATH=”$PYTHONPATH:your path1:your path2 …”,然后保存.bashrc文件,接着命令行输入指令:source .bashrc,这样会永久声效,如果你开了多个shell窗口,由于其他窗口没有运行source命令,所以需要关闭才能起作用。如果想测试一次,可以命令行输入这句话
    2. window下这台电脑->属性->高级系统设置->环境变量->新建(可以选择在用户变量里加,不用修改系统变量),然后变量名为PYTHONPATH,变量值为你的搜索路径

3.2 关于PyCharm中的模块路径搜索

  1. PyCharm有project(工程)的概念,即创建一个工程之后,会把这个目录自动添加到sys.path里面,但这不是python的概念,因此经常会遇到将PyCharm中创建的这个工程直接放在linux下去运行会搜找不到某个module,因为Linux下并没有把该工程的最顶级目录放在sys.path中,当然你可以使用添加环境变量的方法加入这个工程目录路径。为了兼容,最好使用3.1中代码添加模块路径的方法来实现。
  2. PyCharm里通过点击某个文件夹,右键选择Mark directory as source root->Sources Root,这样操作之后改文件夹就添加到sys.path变量里面了。取消方法Mark directory as source root->Unmark as Sources Root。
  3. PyCharm中点了Run之后,可以配置运行参数(右上角run键左边下拉Edit Configuration),去掉Add content roots to PYTHONPATH的勾,那么该project的顶级目录就不会添加到sys.path。去掉Add source roots to PYTHONPATH的勾,好像不管用,该文件所在目录还是会加到sys.path变量里面。
import sys

print(sys.path)
sys.path.append('..')  # 添加上级目录为模块搜索路径
sys.path.append('../..')  # 添加上上级目录为模块搜索路径
print(sys.path)

结果

sys.path ['D:\\DeepLearning\\workspaces\\test\\learnimport', 'D:\\DeepLearning\\workspaces\\test\\learnimport', 'D:\\Anaconda3\\python35.zip', 'D:\\Anaconda3\\DLLs', 'D:\\Anaconda3\\lib', 'D:\\Anaconda3', 'D:\\Anaconda3\\lib\\site-packages', 'D:\\Anaconda3\\lib\\site-packages\\Sphinx-1.4.6-py3.5.egg', 'D:\\Anaconda3\\lib\\site-packages\\setuptools-36.6.0-py3.5.egg']

modified sys.path ['D:\\DeepLearning\\workspaces\\test\\learnimport', 'D:\\DeepLearning\\workspaces\\test\\learnimport', 'D:\\Anaconda3\\python35.zip', 'D:\\Anaconda3\\DLLs', 'D:\\Anaconda3\\lib', 'D:\\Anaconda3', 'D:\\Anaconda3\\lib\\site-packages', 'D:\\Anaconda3\\lib\\site-packages\\Sphinx-1.4.6-py3.5.egg', 'D:\\Anaconda3\\lib\\site-packages\\setuptools-36.6.0-py3.5.egg',  '..', '../..']

注意sys.path[0]是该文件所在目录,modified之后的list后面多了’..’, ‘../..’

3.3 PyCharm编写代码和Linux下编写代码兼容问题

  1. 还是上面提到的搜索路径问题,使用sys.path.append(path_name)
  2. PyCharm引用另一个文件一般都是从顶级目录(即project目录)开始一步一步往下,如:from learnimport.model.tfmodel import *。注意:Linux下,为了让文件在工程的其他目录下都可以运行,请在要运行的文件中将顶级目录添加到搜索路径。当然也可以把要运行的代码都放在顶级目录下,就不用添加这个搜索路径了。
  3. 举例:
    目录结构如下:
learnimport/  # 顶级目录0
    --model/  # 1
        --get_model.py  
        --tfmodel/  # 2
            --testmodel/  # 3
                --work.py  
  --tools/  # 1
    --readcsv.py

调用关系如下:

Created with Raphaël 2.1.2 work.py get_model.py readcsv.py

work.py添加learnimport到搜索路径

sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../..'))

get_model.py添加learnimport到搜索路径

sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))

readcsv.py添加learnimport到搜索路径

sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))

二、解决一个文件引用另一个文件,另一个文件open另一个文件错误问题

1、 test.py文件内容如下:

import os
import sys

sys.path.append('..')  # 添加搜索路径到顶级目录
# 使用下面这语句将适应任何情况,一定会指向顶级目录learnimport,不会因为工作目录的原因导致‘..’指向错误的目录,但看着相对复杂
# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from tools.readcsv import readresult

if __name__ == '__main__':
    print('test getcwd', os.getcwd())
    readresult()

2、 readcsv.py文件内容如下:

import csv
import os


def readresult(path=None):
    """read the csv file and print every row

    Args:
        path: A str, path of csv file, if is None, set path to result.csv

    Returns:

    """
    if path is None:
        path = 'result.csv'
    with open(path, 'r', newline='') as f:
        reader = csv.reader(f)
        for v in reader:
            print(v)

3、 result.csv文件内容如下:

jason,male,25
cherish,female,22

输出结果:

test getcwd D:\DeepLearning\workspaces\test\learnimport\test
Traceback (most recent call last):
  File "D:/DeepLearning/workspaces/test/learnimport/test/test.py", line 8, in <module>
    readresult()
  File "D:\DeepLearning\workspaces\test\learnimport\tools\readcsv.py", line 16, in readresult
    with open(path, 'r', newline='') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'result.csv'
会报错

4、 解决问题:

  1. 首先引入这个文件成功,在win,linux,pycharm都可以引入
import sys

sys.path.append('..')  # 添加搜索路径到顶级目录
from tools.readcsv import readresult
  1. 为什么open(‘result.csv’, ‘r’, newline=”)打不开呢,明明result.csv和readcsv.py在同一级目录下,却说找不到。

原因:由于工作目录导致的。测试可知,运行test.py文件readcsv.py的工作目录和test.py工作目录是一样的,需要修改readcsv.py的工作目录为它自己的当前目录才能正确的open,也可以open一个具体的路径。

其实原因虽然是工作目录导致的,但可以通过给open函数传入具体路径的方法来防止工作目录不同导致打不开文件的情况

修改test.py文件代码如下:

import os
import sys

# sys.path.append('..')  # 添加搜索路径到顶级目录
# 使用下面这语句将适应任何情况,一定会指向顶级目录learnimport,不会因为工作目录的原因导致‘..’指向错误的目录,但相对看着复杂
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  # new line
from tools.readcsv import readresult

if __name__ == '__main__':
    print('test cwd', os.getcwd())
    readresult()
    print('modified test cwd', os.getcwd())  # new line

修改readcsv.py代码如下:

import csv
import os


def readresult(path=None):
    """read the csv file and print every row

    Args:
        path: A str, path of csv file, if is None, set path to result.csv

    Returns:

    """
    currcwd = os.getcwd()  # new line
    print('readcsv cwd', currcwd)  # new line
    if path is None:
        path = 'result.csv'
    os.chdir(os.path.dirname(os.path.abspath(__file__)))  # new line
    print('change working dir', os.getcwd())  # new line
    with open(path, 'r', newline='') as f:
        reader = csv.reader(f)
        for v in reader:
            print(v)
    os.chdir(currcwd)  # new line 把工作目录改回去防止出现其他错误

结果:

test getcwd D:\DeepLearning\workspaces\test\learnimport\test
readcsv cwd D:\DeepLearning\workspaces\test\learnimport\test
change working dir D:\DeepLearning\workspaces\test\learnimport\tools
['jason', 'male', '25']
['cherish', 'female', '22']
modified test cwd D:\DeepLearning\workspaces\Test\learnimport\tools

由于修改了工作目录后会一直是修改之后的工作目录,所以最好在open之后改回来,防止出现其他错误

方法2 修改open打开路径为result.csv的具体路径

import csv
import os


def readresult(path=None):
    """read the csv file and print every row

    Args:
        path: A str, path of csv file, if is None, set path to result.csv

    Returns:

    """
    if path is None:
        path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'result.csv')  # modified line
    with open(path, 'r', newline='') as f:
        reader = csv.reader(f)
        for v in reader:
            print(v)

猜你喜欢

转载自blog.csdn.net/u014734886/article/details/79943401