Python:如何从序列化形式重建对象而无需重新计算属性
推荐实现方案
1. 类工厂方法(最推荐,扩展性强)
给Link类添加一个类方法,直接从字典(JSON解析后的数据)创建实例,跳过原__init__里的自动生成ID和爬取逻辑:
from uuid import uuid4 as uuid import requests from bs4 import BeautifulSoup class Link: def __init__(self, url): self.url = url self.id = str(uuid()) self.content = self.scrape() def scrape(self): response = requests.get(self.url).text soup = BeautifulSoup(response, features="html.parser") return soup.get_text() @classmethod def from_dict(cls, data): # 创建实例但不调用__init__,避免触发scrape和ID生成 instance = cls.__new__(cls) # 直接将字典中的所有属性赋值给实例 instance.__dict__.update(data) return instance
使用时,把JSON解析成字典后传入即可:
import json # 从数据库读取的JSON字符串 json_str = '''{ "url": "https://example.com", "id": "ba664ae1-eb5d-4370-9276-93f8d9d03a0d", "content": "Example Domain Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. More information..." }''' data = json.loads(json_str) link_obj = Link.from_dict(data)
这种方式不管后续新增多少字段(比如title),只要JSON里包含对应的键,就能自动赋值,完全不用修改工厂方法,扩展性极强。
2. 改用dataclass的简化方案
如果后续换成dataclass,可以结合类工厂方法,同样不用修改核心逻辑:
from dataclasses import dataclass from uuid import uuid4 as uuid import requests from bs4 import BeautifulSoup @dataclass class Link: url: str id: str | None = None content: str | None = None def __post_init__(self): # 只有当id或content为空时,才执行自动生成和爬取逻辑 if self.id is None: self.id = str(uuid()) if self.content is None: self.content = self.scrape() def scrape(self): response = requests.get(self.url).text soup = BeautifulSoup(response, features="html.parser") return soup.get_text() @classmethod def from_dict(cls, data): return cls(**data)
这里利用__post_init__区分首次创建和从数据库重建的场景:首次实例化时不传id和content,就自动生成/爬取;从JSON重建时直接传入所有字段,__post_init__不会触发额外逻辑。from_dict只需要解包字典即可,新增字段时也不需要修改这个方法。
为什么不推荐修改__init__参数?
如果直接给__init__加一堆可选参数(比如id=None, content=None),后续每加一个字段都要修改__init__的参数列表,代码会越来越臃肿,维护成本高。而工厂方法的模式可以彻底避免这个问题。
内容的提问来源于stack exchange,提问作者theo
相关产品推荐
相关产品推荐

