Effective Python系列(1.1):区别bytes和str

本篇文章是 Effective Python 这本书的第一章,本章的主要内容是什么样的代码风格才是比较符合 Python 语言。

Python 当中,bytesstr 是两种不同的数据结构。使用时,需要注意两者区别:

  1. bytes 包含的是由 8 位值所组成的序列,而 str 包含的是由 Unicode 字符组成的序列,可以指定解码格式,如 utf-8

  2. bytesstr 之间的转换,可以使用 encode()decode() 方法。

  3. bytesstr 这两种实例不能在某些操作符(例如>、==、+、%操作符)上混用

  4. 从文件读取或者写入二进制数据时,应该以 'rb'(或者'wb')这样的二进制模式打开文件

  5. 如果要从文件中读取/写入的是 Unicode 数据,则必须注意系统采用的默认编码方案。可以使用下面的代码判断:

import sys
sys.getdefaultencoding()

下面写了两个程序:

  1. 测试 bytesstr 之间的相互转换。
  2. 命令行程序:测试文件的创建、读取、写入和删除。该程序最大的亮点是提供了简易的自动补全功能。
import sys
import json
from pathlib import Path
from prompt_toolkit import prompt
from prompt_toolkit.completion import Completer, Completion


def to_str(data, encoding="utf-8"):
    """
    将字节数据转换为字符串。

    参数:
    data: 字节数据
    encoding: 字符串的编码格式,默认为utf-8

    返回:
    转换后的字符串
    """
    if isinstance(data, bytes):
        return data.decode(encoding)
    elif isinstance(data, str):
        return data
    else:
        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 data
    else:
        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_name
            self.file_path.rename(new_path)
            self.file_path = new_path
            print(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} 不存在.")
                return
            self.file_path.rename(new_path)
            self.file_path = new_path
            print(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":
            break
        elif command == "update":
            new_data = input("请输入新的JSON数据: ")
            try:
                # 对用户输入的JSON数据进行验证
                new_data = json.loads(new_data)
                manager.update(new_data)
            except json.JSONDecodeError:
                print("输入的JSON数据格式错误")
                continue
        elif 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()

程序使用例子:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值