如何将Python自定义类和内置类实例存为字符串?eval报错如何解决
问题根因说明
你代码触发报错的核心原因是自定义类没有重写__str__或__repr__方法时,str(i)默认输出的是<__main__.TestClass object at 0x7f9b1c0d5150>这类不合法的Python表达式,自然无法被eval解析。而int、float等内置类型的字符串输出本身就是合法字面量,所以可以被eval正常执行。
可选用的实现方案
方案1:重写__repr__适配eval
这是改动最小的适配方案,只要给自定义类实现__repr__方法,返回可重新构造实例的表达式即可:
class TestClass: def __init__(self, number): self.number = number def __repr__(self): # 返回的字符串要和构造实例的代码逻辑一致 return f"TestClass({self.number})" i = TestClass(14) str_i = str(i) print(eval(str_i)) # 执行成功,输出实例对象
注意:该方案仅适合处理可信来源的字符串,eval执行不可信字符串会带来严重的代码注入风险,同时需要每个自定义类单独实现__repr__方法。
方案2:使用pickle序列化(Python专属方案)
如果不需要序列化结果人类可读,也不需要跨语言交互,标准库pickle是最省心的方案,支持所有Python内置类型和自定义类,不需要修改类定义:
import pickle import base64 class TestClass: def __init__(self, number): self.number = number # 序列化:实例转可存储的字符串 i = TestClass(14) bytes_data = pickle.dumps(i) str_i = base64.b64encode(bytes_data).decode('utf-8') # 二进制转base64文本方便存储 # 反序列化:字符串转实例 restored_i = pickle.loads(base64.b64decode(str_i)) print(restored_i.number) # 输出14
注意:pickle同样存在安全风险,不要加载来源不明的pickle序列化数据。
方案3:JSON序列化(通用可读方案)
如果需要序列化结果可读、跨语言兼容、安全性更高,可以用json模块搭配自定义编解码逻辑:
import json class TestClass: def __init__(self, number): self.number = number # 自定义序列化编码器 class CustomEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, TestClass): # 加类型标记,反序列化时识别 return {"__type__": "TestClass", "number": obj.number} return super().default(obj) # 自定义反序列化解码器 def custom_decoder(dct): if dct.get("__type__") == "TestClass": return TestClass(dct["number"]) return dct # 序列化 i = TestClass(14) str_i = json.dumps(i, cls=CustomEncoder) print(str_i) # 输出 {"__type__": "TestClass", "number": 14} # 反序列化 restored_i = json.loads(str_i, object_hook=custom_decoder) print(restored_i.number) # 输出14
该方案的优势是安全可控,序列化结果可读性强,还支持跨语言交互,缺点是新增自定义类时需要同步修改编解码逻辑。
内容的提问来源于stack exchange,提问作者kethan1
相关产品推荐
相关产品推荐

