zl程序教程

您现在的位置是:首页 >  Python

当前栏目

Python 越来越优雅了

2023-02-18 16:34:20 时间

背景

前些天无意中看到了一个开源项目的代码,由衷感叹 Python 的语法是真的越来越优雅了。还是说回代码,项目中作者想拼接两个字符串作为文件的路径,他是这样写的。

log_file = tmp_dir / "err.log"

with open(log_file) as file_obj:
    # 省去若干代码

我觉得这段代码的亮点在于第一行,初看像是除法,但是实际上是路径拼接。这一行非常好的使用到了 "/" 这个运算符重载,简直是传神了极了。

之所以让我有这么深的感触,是因为在路径的处理上我的认识也经历过好几次的革新。下面就写一下这些年的经历吧。


约定

为了方便后面的讲述,我们假设要在程序的当前目录下创建一个子目录 txts , 并且向 txts 目录下的 message.txt 中写入 “hello world” 这个字符串。也就是说最终是这样的一个目标结构。

├── main.py
└── txts
    └── message.txt

1 directory, 2 files

第一重认识

一开始的时候我认为路径只是一个特别一点的字符串,别的就没有什么了。这个就会导致写出的代码不灵活。

#!/usr/bin/env python3
# -*- coding: utf8 -*-

import os

def main():
    # 取得当前目录
    current_dir = os.path.dirname(__file__)

    # 创建 txts 子目录
    txts_dir = current_dir + "/" + "txts"
    if not os.path.isdir(txts_dir):
        os.mkdir(txts_dir)

    # 向文件中写入 "hello world"
    message_file = txts_dir + "/" + "message.txt"
    with open(message_file, 'w') as file_obj:
        file_obj.write("hello world\n")


if __name__ == "__main__":
    main()
    

后来发现不对,代码有可能运行在 windows 上,"/" 导致不能跨平台。


第二重认识

在意识到代码要在 windows 上运行后,知道不能再用 "/" 来分隔路径了,改成了 os.path.sep 这个平台无关的变量;这里自己定义也行,只是标准库已经提供了,就没有必要自己再造一下轮子。

#!/usr/bin/env python3
# -*- coding: utf8 -*-
import os

def main():
    # 取得当前目录
    current_dir = os.path.dirname(__file__)
    # 创建 txts 子目录
    txts_dir = os.path.sep.join([current_dir, "txts"])
    if not os.path.isdir(txts_dir):
        os.mkdir(txts_dir)

    # 向文件中写入 "hello world"
    message_file = os.path.sep.join([txts_dir, "message.txt"])
    with open(message_file, 'w') as file_obj:
        file_obj.write("hello world\n")

if __name__ == "__main__":
    main()

这个方案虽然解决了跨平台的问题,但是代码还是太长了,并不优雅。主要表现在,看到代码还要想一下,才能知道这是在拼接路径。


第三重认识

后来社区就有了 pathlib 这个库,真可谓是所见即所得呀!

#!/usr/bin/env python3
# -*- coding: utf8 -*-
import os
from  pathlib import Path

def main():
    # 创建 txts 子目录
    txts_dir = Path(__file__).parent / "txts"
    if not txts_dir.exists():
        os.mkdir(txts_dir)

    # 向文件中写入 "hello world"
    with open(txts_dir / "message.txt", 'w') as file_obj:
        file_obj.write("hello world\n")

if __name__ == "__main__":
    main()

自从,重载了 "/" 之后代码简明多了,我在 windows 上也试了下,这个确实是跨平台的。