Python中如何检测Avro联合字段的实际类型?
如何在Python中检测Avro联合类型字段的实际类型
当然可以检测!问题出在你当前的读取方式把Avro的类型信息完全丢弃了,只保留了纯Python原生值——比如枚举类型的TYPE1和字符串类型的TYPE1看起来一模一样,自然没法区分。下面我用两种最常用的Python Avro库来给你演示解决方案:
一、用官方avro库
官方avro库在反序列化的时候,会把Avro的枚举类型转换成avro.schema.EnumSymbol对象,而字符串就是普通的Python字符串,null则是None。这样通过类型判断就能轻松区分三者:
示例代码
import avro.schema from avro.datafile import DataFileReader, DataFileWriter from avro.io import DatumReader, DatumWriter # 你的Schema定义 schema_str = """{ "namespace":"com.example", "type":"record", "name":"TestObject", "fields":[ { "name":"element", "type": [ "null", "string", { "name":"element_type", "type": "enum", "symbols": ["TYPE1", "TYPE2"] } ], "default":"TYPE1" } ] }""" schema = avro.schema.parse(schema_str) # 先写点测试数据(模拟你的Avro文件) with open("test.avro", "wb") as f: writer = DataFileWriter(f, DatumWriter(), schema) writer.append({"element": None}) writer.append({"element": "TYPE1"}) # 字符串类型的TYPE1 writer.append({"element": schema.fields[0].type.types[2].symbols[0]}) # 枚举类型的TYPE1 writer.append({"element": "TYPE2"}) writer.append({"element": schema.fields[0].type.types[2].symbols[1]}) writer.close() # 读取并检测类型 with open("test.avro", "rb") as f: reader = DataFileReader(f, DatumReader()) for record in reader: element = record["element"] print(f"值: {element}") if element is None: print("实际类型: null") elif isinstance(element, avro.schema.EnumSymbol): print(f"实际类型: enum(element_type),符号: {element}") elif isinstance(element, str): print("实际类型: string") print("---")
关键点
- 枚举类型会被转成
EnumSymbol实例,和普通字符串有明确的类型差异 - 直接用
isinstance判断就能区分三种联合类型
二、用fastavro库(更快的替代方案)
fastavro默认会把枚举转成字符串,导致无法区分,但你可以加个参数让它保留枚举类型:
示例代码
from fastavro import writer, reader, parse_schema # 解析你的Schema schema = parse_schema({ "namespace":"com.example", "type":"record", "name":"TestObject", "fields":[ { "name":"element", "type": [ "null", "string", { "name":"element_type", "type": "enum", "symbols": ["TYPE1", "TYPE2"] } ], "default":"TYPE1" } ] }) # 写入测试数据 with open("test_fast.avro", "wb") as f: writer(f, schema, [ {"element": None}, {"element": "TYPE1"}, # 字符串类型 {"element": schema["fields"][0]["type"][2]("TYPE1")}, # 枚举类型 {"element": "TYPE2"}, {"element": schema["fields"][0]["type"][2]("TYPE2")}, ]) # 读取时开启保留枚举类型 with open("test_fast.avro", "rb") as f: for record in reader(f, use_enum=True): element = record["element"] print(f"值: {element}") if element is None: print("实际类型: null") elif isinstance(element, schema["fields"][0]["type"][2]): print(f"实际类型: enum(element_type),符号: {element}") elif isinstance(element, str): print("实际类型: string") print("---")
关键点
- 加上
use_enum=True参数后,fastavro会把Avro枚举转成对应的Python枚举类实例 - 这样就能轻松区分字符串和枚举类型
为什么你的现有代码不行?
如果你的代码读取后得到的是纯字典,说明反序列化时已经把Avro的类型信息丢弃了(比如fastavro默认把enum转成字符串,或者你手动把记录转成了纯原生类型)。只要在读取时保留类型信息,就能准确判断每个字段的实际类型。
内容的提问来源于stack exchange,提问作者Jonny5
相关产品推荐
相关产品推荐

