Python:操作路径时不同操作系统的问题

518 阅读3分钟

01 | 问题描述

最近有一个需求,需要自动地导入某一个文件夹的.py文件,例如:

--app
----model
------__init__.py
------a.py
------b.py
--__init__.py

具体的需求是:在app__init__.py文件中批量导入model文件夹中的.py文件,之前的实现方式(主要是借助__import__)是:

  • model/__init__.py
import os
import pkgutil

pkg_path, _ = os.path.split(os.path.relpath(__file__))

for _, file, _ in pkgutil.iter_modules([pkg_path]):
    __import__(pkg_path.replace("\", ".") + "." + file)
  • app/__init__.py
from app.model import *

Windows开发环境中没有一切正常,但是运行在Centos服务器中报错:No module named 'app/model'

02 | 问题定位

model/__init__.py文件的第7行之前添加2行内容,分别查看pkg_pathfile的内容:

  • model/__init__.py
import os
import pkgutil

pkg_path, _ = os.path.split(os.path.relpath(__file__))

for _, file, _ in pkgutil.iter_modules([pkg_path]):
    print(pkg_path)
    print(file)
    __import__(pkg_path.replace("\", ".") + "." + file)

Windows操作系统中pkg_path打印值为:app\modelCentos操作系统的打印值为:app/model,也就说,之前的pkg_path.replace("\", ".")Centos操作系统中没有起作用。

03 | 解决方法

03-1 | 根据当前运行的平台确定替换内容

简单的来讲,首先通过Python语句判断当前系统运行的平台,是Windows还是Linux系统,然后根据平台确定要替换的内容,Windows就替换``,Linux就替换/,具体代码如下:

import os
import pkgutil
import platform

pkg_path, _ = os.path.split(os.path.relpath(__file__))
platform_system = platform.system().lower

for _, file, _ in pkgutil.iter_modules([pkg_path]):
    if platform_system == "windows"
    	__import__(pkg_path.replace("\", ".") + "." + file)
    elif platform_system == "linux":
        __import__(pkg_path.replace("/", ".") + "." + file)

但这种方式总感觉不是很优雅,每次遍历总要做if-else判断。

03-2 | 统一pkg_path的格式

无论在哪种操作系统下,统一pkg_path的值(也就是绝对路径)为一个格式,例如:Linux系统的格式。大概有两种方式,一种是获得pkg_path的值以后,调用replace方法,将Windows系统中的``替换为/;另一种是调用pathlib.PurePath.as_posix()方法,这个是Python 3.4新增的方法。第一种方法比较简单,代码参考__import__语句中的方法即可。这里列出第二种方法的代码:

# !/venv/Scripts/python
# -*- coding: utf-8 -*-
# @Time : 2022/02/10
# @Author : Jiao Xiang Ning
# @Email : jiaoxn@geoscene.cn
# @File  : __init__.py.py

import os
import pkgutil

from pathlib import Path

pkg_path, _ = os.path.split(os.path.relpath(__file__))
pkg_path = Path(pkg_path).as_posix()  # 统一路径格式为Unix格式

for _, file, _ in pkgutil.iter_modules([pkg_path]):
    __import__(pkg_path.replace("/", ".") + "." + file)

04 | 技术探秘

pathlib是从Python 3.4开始引入的,在Python 3.6已经基本成熟了。pathlib是面向对象的文件系统路径工具,提供了表示文件系统的类,这些类具有适用于不同操作系统的语义,官网地址

pathlib中的路径类分为2种:纯路径和具体路径,纯路径(PurePath)没有I/O的计算操作,具体路径从PurePath中继承并提供了I/O操作。如果之前没用过pathlib或者不知道用哪个类,大部分情况下可直接使用Path类。

pathlib相对于之前的os.path有这个几个优势:

  1. 之前的os.path操作函数管理比较混乱,有的是导入os,有的是导入os.pathpathlib只需要导入pathlib
  2. os.path在多个操作系统间切换比较麻烦,通常还会需要修改部分代码;pathlib很方便
  1. os.path返回值通常是字符串,但是路径和字符串并非完全等价,之前要操作路径时可能需要额外的操作;pathlib模块是面向对象,处理更灵活
  2. pathlib简化了很多操作

来几个示例对比一下吧:

  1. 获取当前路径:
  • os.path
import os
print(os.getcwd()) # C:\Users\jiaoxn\Desktop\example
  • pathlib
import pathlib
print(pathlib.Path.cwd())
  1. 拼接路径
  • os.path
import os
print(os.path.join("a", "b"))
  • pathlib
import pathlib

paths = ["a", "b"]
print(pathlib.Path().parent.joinpath(paths))

\