本篇文章是 Effective Python
这本书的第一章,本章的主要内容是什么样的代码风格才是比较符合 Python
语言。
在 Python
当中,bytes
和 str
是两种不同的数据结构。使用时,需要注意两者区别:
-
bytes
包含的是由 8 位值所组成的序列,而str
包含的是由Unicode
字符组成的序列,可以指定解码格式,如utf-8
。 -
bytes
和str
之间的转换,可以使用encode()
和decode()
方法。 -
bytes
和str
这两种实例不能在某些操作符(例如>、==、+、%操作符)上混用 -
从文件读取或者写入二进制数据时,应该以
'rb'
(或者'wb'
)这样的二进制模式打开文件 -
如果要从文件中读取/写入的是
Unicode
数据,则必须注意系统采用的默认编码方案。可以使用下面的代码判断:
import sys
sys.getdefaultencoding()
下面写了两个程序:
- 测试
bytes
和str
之间的相互转换。 - 命令行程序:测试文件的创建、读取、写入和删除。该程序最大的亮点是提供了简易的自动补全功能。
import sys
import json
from pathlib import Path
from prompt_toolkit import prompt
from prompt_toolkit.completion import Completer, Completiondef to_str(data, encoding="utf-8"):"""将字节数据转换为字符串。参数:data: 字节数据encoding: 字符串的编码格式,默认为utf-8返回:转换后的字符串"""if isinstance(data, bytes):return data.decode(encoding)elif isinstance(data, str):return dataelse:raise TypeError(f"Expected bytes, got {type(data)}")def to_bytes(data, encoding="utf-8"):"""将字符串转换为字节数据。参数:data: 字符串数据encoding: 字节编码格式,默认为utf-8返回:转换后的字节数据"""if isinstance(data, str):return data.encode(encoding)elif isinstance(data, bytes):return dataelse:raise TypeError(f"Expected str, got {type(data)}")class JsonFileManager:def __init__(self, file_path):"""初始化文件管理器。参数:file_path: 文件路径"""self.file_path = Path(file_path).resolve() # 转换为绝对路径def create(self):"""创建一个空的JSON文件。"""try:if not self.file_path.exists():with open(self.file_path, 'w') as f:json.dump({}, f, indent=4)print(f"文件 {self.file_path.name} 已创建。")else:print(f"文件 {self.file_path.name} 已存在。")except (IOError, PermissionError) as e:print(f"创建文件失败: {e}")def read(self):"""读取并显示JSON文件的内容。"""try:if self.file_path.exists():with open(self.file_path, 'r') as f:data = json.load(f)print("读取的文件内容:", data)else:print(f"文件 {self.file_path.name} 不存在。")except (IOError, json.JSONDecodeError) as e:print(f"读取文件失败: {e}")def delete(self):"""删除文件。"""try:if self.file_path.exists():self.file_path.unlink()print(f"文件 {self.file_path.name} 已删除。")else:print(f"文件 {self.file_path.name} 不存在。")except (IOError, PermissionError) as e:print(f"删除文件失败: {e}")def update(self, data):"""更新文件内容。"""try:with open(self.file_path, 'w') as f:json.dump(data, f, indent=4)print(f"文件 {self.file_path.name} 已更新。")except (IOError, PermissionError) as e:print(f"更新文件失败: {e}")def rename(self, new_name):"""重命名文件。"""try:new_path = self.file_path.parent / new_nameself.file_path.rename(new_path)self.file_path = new_pathprint(f"文件已重命名为 {new_name}.")except (FileNotFoundError, PermissionError) as e:print(f"重命名文件失败: {e}")def move(self, new_path):"""移动文件到新位置。"""try:new_path = Path(new_path).resolve()if not new_path.parent.exists():print(f"目标路径 {new_path.parent} 不存在.")returnself.file_path.rename(new_path)self.file_path = new_pathprint(f"文件已移动到 {new_path}.")except (FileNotFoundError, PermissionError) as e:print(f"移动文件失败: {e}")# 定义命令补全的列表
COMMANDS = ["create", "read", "delete", "update", "rename", "move", "quit"]class CommandCompleter(Completer):def __init__(self):self.commands = COMMANDS # 定义可补全的命令列表def get_completions(self, document, complete_event):"""返回与输入的部分文本匹配的命令。"""text = document.text.strip()for command in self.commands:if command.startswith(text):yield Completion(command, start_position=-len(text))def setup_readline():"""配置自动补全功能。"""completer = CommandCompleter()# 使用prompt_toolkit的prompt函数获取输入,并启用自动补全user_input = prompt('请输入命令(create, read, delete, update, rename, move, quit): ', completer=completer)return user_input def main():"""主函数,处理文件操作与字节数据转换。"""# setup_readline()file_path = input("请输入文件路径: ").strip()# file_path = 'dataset.json'manager = JsonFileManager(file_path)while True:command = setup_readline().strip().lower()if command == "quit":breakelif command == "update":new_data = input("请输入新的JSON数据: ")try:# 对用户输入的JSON数据进行验证new_data = json.loads(new_data)manager.update(new_data)except json.JSONDecodeError:print("输入的JSON数据格式错误")continueelif command in ["create", "read", "delete", "rename", "move"]:if command == "rename":new_name = input("请输入新的文件名: ").strip()manager.rename(new_name)elif command == "move":new_location = input("请输入新的文件路径: ").strip()manager.move(new_location)else:getattr(manager, command)()else:print("无效命令,请输入 'create', 'read', 'delete', 'update', 'rename', 'move' 或 'quit'")def main2():# 示例:创建一个包含字节数据的文件,并读取它file_path = "test_bytes.json"# 创建 JsonFileManager 实例manager = JsonFileManager(file_path)# 1. 创建文件并写入字节数据manager.create() # 文件已创建,但内容为空 {}# 假设用户想将字符串 "Hello, World!" 转换为字节并写入文件data_to_write = to_bytes("Hello, World!") # 使用 to_bytes 转换为字节流# 更新文件内容,将字节数据以 JSON 格式存储manager.update({"message": data_to_write.hex()}) # 将字节数据转为十六进制字符串存储# 2. 读取文件并将字节数据还原为字符串manager.read() # 输出 { "message": "48656c6c6f2c20576f726c6421" }# 获取 JSON 数据with open(file_path, 'r') as f:data = json.load(f)# 从十六进制字符串转换回字节流message_bytes = bytes.fromhex(data["message"])# 使用 to_str 函数将字节数据转换为字符串message_str = to_str(message_bytes)print(f"读取的消息:{message_str}") # 输出 "Hello, World!"if __name__ == "__main__":main()
程序使用例子: