如何通过Python的__bytes__方法定义类对象的字节序列化?

老辰君_1627

老辰君_1627

2026-07-20

883人浏览

原创

__bytes__ 方法必须返回 bytes 类型,否则抛出 typeerror;它专用于提供对象的规范字节表示(如网络传输),不用于序列化或格式化,且不被 pickle/json 自动调用。

如何通过python的__bytes__方法定义类对象的字节序列化?

__bytes__ 方法必须返回 bytes 类型,否则会报 TypeError

Python 的 __bytes__ 方法不是可选的“增强序列化”,而是明确要求返回 bytes 实例的协议方法。一旦定义了它,调用 bytes(obj) 就会触发该方法;如果返回值不是 bytes(比如 str、bytearray 或 list),Python 会直接抛出 TypeError: __bytes__ returned non-bytes object。

  • 常见错误:在方法里写 return self.data.encode('utf-8') —— 看似合理,但如果 self.data 是数字、None 或非字符串类型,就会崩溃
  • 正确做法:确保所有分支最终都走 bytes() 构造或字面量,例如 b''、struct.pack(...)、json.dumps(...).encode()
  • 注意:不能返回 bytearray,哪怕它和 bytes 行为相似,也必须显式转换:return bytes(my_bytearray)

__bytes__ 和 __str__ / __repr__ 的用途完全不同

__bytes__ 不是 __str__ 的二进制版本,也不是为了“打印好看”。它的语义是:提供该对象在网络传输、文件写入或底层协议中所需的**规范字节表示**。比如你有一个自定义的 IP 地址类,__bytes__ 应该返回 4 字节(IPv4)或 16 字节(IPv6)的原始数据,而不是 b'192.168.1.1' 这种可读字符串。

Forge — Python Developer
Forge — Python Developer

Python开发助手 — 自动化脚本、API封装、命令行工具、数据管道、网页爬虫。经过测试的代码,包含错误处理和文档。当你需要...

下载
  • 场景举例:实现一个轻量级二进制消息头类,字段顺序固定,__bytes__ 直接用 struct.pack('>IHI', self.magic, self.version, self.length)
  • 反例:对日志类、配置类定义 __bytes__ 并返回 JSON 字节流——这属于序列化逻辑,更适合用 json.dumps().encode() 显式调用,而非绑定到 bytes() 协议
  • 兼容性提示:Python 3.10+ 对 __bytes__ 返回值做了更严格的类型检查,旧代码若隐式返回 bytearray 可能突然失效

__bytes__ 不会自动被 pickle 或 json 使用

很多人误以为实现了 __bytes__ 就能让 pickle.dump() 或 json.dump() 自动生效,其实完全不会。pickle 走的是自己的协议(__getstate__、__reduce__ 等),json 只认 dict、list、基本类型和 default 参数指定的转换函数。

  • 如果你希望 pickle 时用字节表示,得单独实现 __reduce__,例如返回 (bytes, (self,))(前提是 self 确实支持 __bytes__)
  • 想让 json 支持,得配 default=lambda obj: obj.__bytes__().hex() if hasattr(obj, '__bytes__') else None,但要注意 hex 编码后已不是原始字节
  • 真正依赖 __bytes__ 的标准操作只有:bytes(obj)、socket.send(obj)(如果 obj 是自定义类)、io.BufferedIOBase.write(obj)

继承内置类型时小心 __bytes__ 的继承行为

如果你的类继承自 int、str 或 bytes,Python 可能跳过你的 __bytes__ 方法。比如子类 class MyInt(int): def __bytes__(self): return b'custom',调用 bytes(MyInt(42)) 仍返回 b'\x00\x00\x00*'(即 int 的默认行为),因为 int 已经实现了 __bytes__ 且不委托给子类。

  • 验证方式:打印 MyInt.__bytes__.__func__,如果指向 int.__bytes__ 而不是你自己定义的方法,说明被覆盖了
  • 绕过办法:不要继承数值类型来“伪装”字节行为;改用组合(has-a)而非继承(is-a),或者显式在需要处调用 your_obj.to_bytes() 这类自定义方法
  • 例外:继承 object 安全,所有用户定义类默认没有 __bytes__,你的实现会被尊重
实际写的时候,最常被忽略的是类型校验和协议边界——__bytes__ 是个契约,不是便利函数。它只服务于明确需要字节流的上下文,别把它当成通用序列化入口。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1731

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4424

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1709

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

25917

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3147

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3167

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1183

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2463

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习