如何判断一个对象是真正的 bytes 而不是 bytearray

10次阅读

最可靠的方法是用 type(obj) is bytes 或 type(obj) is byteArray 直接判断类型,因为 type 无法被运行时覆盖,而 isinstance 和 class__.__name 存在误判风险。

如何判断一个对象是真正的 bytes 而不是 bytearray

type() 直接判断最可靠

pythonbytesbytearray 是两种独立类型,虽然都表示字节序列,但前者不可变、后者可变。最直接的方式就是检查对象的类型本身:

  • type(obj) is bytes —— 严格判断是否为 bytes 类型(推荐)
  • type(obj) is bytearray —— 同理判断是否为 bytearray
  • 避免用 isinstance(obj, bytes):它会对 bytearray 返回 True,因为 bytearray 并不继承bytes,但两者在某些协议(如缓冲区协议)中行为相似,isinstance 在这里反而失去区分意义

别被 __class__ 名字迷惑

obj.__class__.__name__ == 'bytes' 看起来直观,但有风险:

  • 如果对象来自第三方库(比如某些 C 扩展或自定义字节类),可能伪造了 __class__ 名称
  • 用户代码可能动态修改了类名(虽不常见,但 __name__ 不是权威标识)
  • type(obj) 是唯一无法被运行时覆盖的类型标识,比 __class__ 更底层、更可信

实际场景中容易踩的坑

很多函数返回值看似是 bytes,实则可能是 bytearray,尤其涉及 I/O 缓冲或网络收发时:

  • socket.recv() 总是返回 bytes
  • io.BytesIO().getbuffer() 返回的是 memoryview,不是 bytesbytearray
  • array.array('B', ...).tobytes() 返回 bytes;而 .tostring()(已弃用)在旧版本中可能返回 str(Python 2)或报错
  • Struct.unpack() 解包出的字节字段,若原始数据来自可变缓冲区,也可能被误传为 bytearray

性能与语义:为什么必须区分?

二者行为差异直接影响程序正确性:

  • bytes 支持哈希(可用于字典键、集合成员),bytearray 不支持 —— 若误把 bytearraybytes 去做缓存键,会抛 TypeError: unhashable type: 'bytearray'
  • bytearray 可原地修改,bytes 修改会创建新对象;若函数契约要求输入不可变,传入 bytearray 可能引发静默错误或意外副作用
  • 某些 C 扩展(如 zlib.compress())内部依赖缓冲区的不可变性,传入 bytearray 虽不报错,但结果可能因后续修改而错乱

判断的关键不在“长得像不像”,而在“它到底是不是那个类型”。type(x) is bytes 这一行,就是最短、最稳、最不容绕过的答案。

text=ZqhQzanResources