面试题答案
一键面试序列化自定义类对象
- 方法一:定义
__dict__
属性或to_dict
方法 假设我们有一个简单的自定义类Person
:
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
如果直接使用json.dumps(person)
会报错,因为json
模块默认不知道如何处理自定义类对象。
我们可以给Person
类添加一个to_dict
方法,将对象转换为可序列化的字典:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def to_dict(self):
return {
"name": self.name,
"age": self.age
}
person = Person("Alice", 30)
serialized = json.dumps(person.to_dict())
print(serialized)
- 方法二:使用
JSONEncoder
的default
方法
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class CustomEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Person):
return {
"name": o.name,
"age": o.age
}
return super().default(o)
person = Person("Alice", 30)
serialized = json.dumps(person, cls=CustomEncoder)
print(serialized)
反序列化时确保数据的正确性和安全性
- 使用
JSONDecoder
的object_hook
假设我们从上述序列化得到的数据进行反序列化:
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def person_decode(dct):
if "name" in dct and "age" in dct:
return Person(dct["name"], dct["age"])
return dct
serialized = '{"name": "Alice", "age": 30}'
deserialized = json.loads(serialized, object_hook=person_decode)
if isinstance(deserialized, Person):
print(f"Name: {deserialized.name}, Age: {deserialized.age}")
- 数据验证
在
person_decode
函数中,除了检查必要的键是否存在,还可以进行类型验证等操作,比如:
def person_decode(dct):
if "name" in dct and "age" in dct:
if not isinstance(dct["name"], str):
raise ValueError("Name should be a string")
if not isinstance(dct["age"], int):
raise ValueError("Age should be an integer")
return Person(dct["name"], dct["age"])
return dct
- 限制反序列化的数据类型
只反序列化特定结构的数据,避免恶意数据构造复杂对象进行攻击。例如,只允许反序列化简单的字典、列表、字符串、数字等基本类型组成的结构,对于复杂的对象构造(如利用
__import__
等危险操作)进行防范。在object_hook
函数中,对传入的字典结构进行严格检查,确保不会引入安全风险。