Python常用代码片段

# 读写json文件

特别注意编码:

  • 读写文件时建议使用utf8编码,不然中文会乱码

  • json.dump序列化时默认使用ASCII码,想要在json文件中显示中文,需要指定ensure_ascii=False

import json


# 读取json文件
with open(json_file, "r", encoding="utf-8") as f:
    data = json.load(f)

# 写入json文件
with open(json_file, "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False)
1
2
3
4
5
6
7
8
9
10

# 逐行读写文本

with open(file_path, "r", encoding="utf-8") as f:
    lines = f.readlines()
    for i in range(len(lines)):
        do_something()

with open(file_path, "w", encoding='utf8') as f:
    content = "".join(lines)
    f.write(content)
1
2
3
4
5
6
7
8

# 读写csv文件

demo.csv

id,name
1,张三
2,Tom
3,Peter
1
2
3
4

读取csv文件内容:

import csv

with open('demo.csv', 'r', encoding='utf-8')as f:
    csv_reader = csv.reader(f)
    for row in csv_reader:
        print(row)

# output
'''
['id', 'name']
['1', '张三']
['2', 'Tom']
['3', 'Peter']
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14

生成csv文件:

  • 注意编码encoding='utf-8-sig'
  • 如果不写newline='',生成的csv文件中可能会出现很多空行
import csv


data = [
    ['id', 'name'],
    ['1', '张三'],
    ['2', 'Tom'],
    ['3', 'Peter']
]
# 注意这里编码是utf-8-sig
with open('demo.csv', 'w', encoding='utf-8-sig', newline='') as f:
    csv_writer = csv.writer(f)
    for row in data:
        csv_writer.writerow(row)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 配置文件解析器:configparser

官方文档:configparser --- 配置文件解析器 (opens new window)

它可以解析类似 Microsoft Windows INI 这样的文件。

例如长这样:config.ini

# 这是注释
; 这是注释
[Default]
url = https://baidu.com
name = 张三

[Debug]
isDebug = False
1
2
3
4
5
6
7
8

使用方法(这是一个有坑的例子,后面才是常用的方法):

import configparser


config = configparser.ConfigParser()
config.read('config.ini')

for section in config.sections():
    print(f"Section: {section}")
    for key in config[section]:
        print(f"Key: {key} Value: {config[section][key]}")

# Output
# Section: Default
# Key: url Value: https://baidu.com
# Key: name Value: 寮犱笁
# Section: Debug
# Key: isdebug Value: False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

根据上面的例子并且参考官方的解释,有以下几点需要注意:

  • 所有key、value都是以字符串的形式存储,如果需要其它数据类型需要自行转换。

  • 注意读取的时候编码设为utf-8,不然中文会乱码。

  • 默认情况下所有的Key都会被强制转换成小写,想要保持大写参考这里:ConfigParser.optionxform(option) (opens new window)

    image-20220329192428381

下面是解决了以上问题的例子:

import configparser


config = configparser.RawConfigParser()
# 解决Key默认转小写的问题,直接返回原字符串
config.optionxform = lambda option: option
# 解决中文乱码问题,加上utf-8编码
config.read('config.ini', encoding="utf-8")

for section in config.sections():
    print(f"Section: {section}")
    for key in config[section]:
        print(f"Key: {key} Value: {config[section][key]}")

# Output
# Section: Default
# Key: url Value: https://baidu.com
# Key: name Value: 张三
# Section: Debug
# Key: isDebug Value: False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 读写YAML文件

什么是YAML文件:YAML is a human-friendly data serialization language for all programming languages. (opens new window)

例如有config.yaml:

# 这是注释
name: 张三
sex: Male
class: Priest
title: Acolyte
hp: [32, 71]
sp: [1, 13]
gold: 423
inventory:
- a Holy Book of Prayers (Words of Wisdom)
- an Azure Potion of Cure Light Wounds
- a Silver Wand of Wonder
1
2
3
4
5
6
7
8
9
10
11
12

Python读写yaml文件的方式:

import yaml
from pprint import pprint


# 读取
with open("config.yaml", "r", encoding="utf-8") as f:
    data = yaml.safe_load(f)

pprint(data)


# 写入
with open("test.yaml", "w", encoding="utf-8") as f:
    yaml.safe_dump(data, f, allow_unicode=True)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

输出:

{'class': 'Priest',
 'gold': 423,
 'hp': [32, 71],
 'inventory': ['a Holy Book of Prayers (Words of Wisdom)',
               'an Azure Potion of Cure Light Wounds',
               'a Silver Wand of Wonder'],
 'name': '张三',
 'sex': 'Male',
 'sp': [1, 13],
 'title': 'Acolyte'}
1
2
3
4
5
6
7
8
9
10

# 获取某个文件夹中的所有文件

  • os.listdir获取指定目录下第一层的所有文件名列表,包括文件夹和文件
  • 生成指定文件的路径用os.path.join,可以避免操作系统路径分隔符不同的问题
import os


folder_path = "./"
# 获取某个文件夹中所有文件列表
file_list = os.listdir(folder_path)
# 区分文件和文件夹
folders = []
files = []
for file in file_list:
    file_path = os.path.join(folder_path, file)
    if os.path.isdir(file_path):
        folders.append(file)
    else:
        files.append(file)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# logging模块的使用

logging模块 (opens new window)是Python官方的日志记录工具。

格式化可用的属性:LogRecord 属性 (opens new window)

记录一下我常用的格式,已封装成一个模块:fine_logger.py

from logging import *


class FineLogger(Logger):

    def __init__(self, name, level=NOTSET):
        Logger.__init__(self, name=name, level=level)

    def init_log_file(self, log_path="debug.log"):
        """
        如果要同时把日志记录到文件中,需要通过此方法设置路径
        :param log_path: 日志文件路径
        """
        # 使用FileHandler把日志输出到文件
        file_handler = FileHandler(log_path, encoding='utf-8')
        file_handler.setFormatter(formatter)
        self.addHandler(file_handler)


fine_logger = FineLogger("root")
# log级别
fine_logger.setLevel(INFO)
# 设置格式
formatter = Formatter('%(asctime)s thread-%(threadName)s %(module)s [%(levelname)s] %(message)s',
                      datefmt='%Y-%m-%d %H:%M:%S')
# 使用StreamHandler把日志输出到控制台
stream_handler = StreamHandler()
stream_handler.setFormatter(formatter)
fine_logger.addHandler(stream_handler)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

使用时只需要导入fine_logger模块:app.py

from fine_logger import fine_logger


# 如果要同时把日志记录到文件中,需要先设置日志路径,默认是./debug.log
fine_logger.init_log_file()
fine_logger.info("Hello")
1
2
3
4
5
6

输出格式如下:

2022-03-22 22:40:56 thread-MainThread app [INFO] Hello
1

# 使用traceback打印异常信息

捕获异常时如果直接打印str(e)得到的信息很少,而使用traceback可以打印出堆栈信息。

官方文档:traceback --- 打印或检索堆栈回溯 (opens new window)

demo.py

import traceback


try:
    a = 1/0
except Exception as e:
    print(traceback.format_exc())
1
2
3
4
5
6
7

output:

注意这里是打印出了异常的堆栈信息,程序并没有异常中断

Traceback (most recent call last):
  File "**/demo.py", line 5, in <module>
    a = 1/0
ZeroDivisionError: division by zero
1
2
3
4

# 获取当前时间戳

更多格式可以参考文档:time.strftime(format[, t]) (opens new window)

print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
# 2022-03-25 15:48:51
1
2

# 生成requirements.txt

python -m pip freeze > requirements.txt
1

# subprocess模块

subprocess是Python标准库中的一个模块,用于在Python程序中创建子进程并与其交互。

subprocess模块提供了多个函数和类,可以方便地执行外部命令,获取命令的输出和错误信息,以及向命令传递输入。其中比较常用的函数包括:

  • subprocess.run(): 执行外部命令并等待其完成,返回一个CompletedProcess对象,包括命令的退出状态码、标准输出、标准错误等信息。
  • subprocess.call(): 执行外部命令并等待其完成,返回命令的退出状态码。
  • subprocess.check_call(): 执行外部命令并等待其完成,如果命令的退出状态码不为0则抛出异常。
  • subprocess.check_output(): 执行外部命令并等待其完成,返回命令的标准输出。
  • subprocess.Popen(): 执行外部命令,返回一个Popen对象,可以通过该对象的方法和属性与子进程交互,例如向其输入数据、发送信号等。

subprocess模块的使用可以避免在Python程序中使用os.system()和os.popen()等函数执行外部命令,能够更加方便地获取命令的输出和错误信息,并且具有更好的跨平台性。

import subprocess


def execute_command(command):
    """
    执行一条shell命令
    """
    print(f"Execute Command: {command}")
    result = subprocess.run(args=command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(f"stdout:\n{result.stdout.decode('utf-8')}")
    if result.returncode != 0:
        raise Exception(f"stderr:\n{result.stderr.decode('utf-8')}")
1
2
3
4
5
6
7
8
9
10
11
12

注意:

  • shell=True:意为通过 shell 来执行命令,此时可以把命令和参数写在一个字符串中,如果使用默认值false,则命令和参数必须分开写。