Python中使用dataclasses与继承正确更新__repr__的方法
问题原因与解决方法
核心问题
你在__repr__里用super().isbn是错误的——父类BookMetadata的属性是实例属性,不是父类的类属性,直接通过self.isbn访问即可,不需要通过super()。super()主要用于调用父类的方法,而非直接访问实例属性。
修复后的__repr__方法
def __repr__(self) -> str: '''Update representation including parent and child class attributes.''' return f'RetailPrice(isbn={self.isbn}, title={self.title}, author={self.author}, publisher={self.publisher}, date_published={self.date_published}, price_usd={self.price_usd}, price_aud={self.price_aud}, price_eur={self.price_eur}, price_gbp={self.price_gbp})'
优化你的dataclass用法
你的子类RetailPrice加了@dataclass()装饰器但手动编写__init__,违背了dataclass的设计初衷,会导致自动生成的方法失效,还容易引发问题。正确做法是让dataclass自动生成构造方法:
优化后的完整代码
from dataclasses import dataclass from typing import Any from datetime import datetime @dataclass class BookMetadata: '''Parent class.''' isbn: str title: str author: str publisher: str date_published: int def format_time(self, unix: int) -> str: '''Convert unix time to %Y-%m-%d.''' return datetime.fromtimestamp(int(str(unix)[0:10])).strftime('%Y-%m-%d') def __post_init__(self): '''Change attributes after assignment.''' # 把UNIX时间转为YYYY-MM-DD格式 self.date_published = self.format_time(self.date_published) @dataclass class RetailPrice(BookMetadata): '''Child class.''' price_usd: float price_aud: float price_eur: float price_gbp: float def stringify(self, obj: Any) -> str: '''Turn object into string.''' return str(obj) def __post_init__(self): '''Change attribute values after assignment.''' # 先执行父类的__post_init__处理日期 super().__post_init__() self.price_usd = self.stringify(self.price_usd) def __repr__(self) -> str: '''Update representation including parent and child class attributes.''' return f'RetailPrice(isbn={self.isbn}, title={self.title}, author={self.author}, publisher={self.publisher}, date_published={self.date_published}, price_usd={self.price_usd}, price_aud={self.price_aud}, price_eur={self.price_eur}, price_gbp={self.price_gbp})'
优化点说明
- 删掉子类手动编写的
__init__,dataclass会自动生成包含父类+子类所有字段的构造方法,无需手动调用父类__init__。 - 子类
__post_init__先调用super().__post_init__(),确保父类的日期转换逻辑优先执行,再处理子类自身属性。 __repr__直接用self.xxx访问所有属性——实例继承了父类的全部实例属性,不管父类还是子类属性都能通过self直接获取。
为什么super().isbn会报错
super()返回的是代理对象,仅能访问父类的类属性或方法;而isbn是实例化后绑定到self上的实例属性,所以通过super()无法访问,必须直接用self。
内容的提问来源于stack exchange,提问作者FaCoffee
相关产品推荐
相关产品推荐

