实例化dataclass时触发NameError的原因分析与解决办法
问题原因分析
你遇到的NameError核心原因是dataclass的默认字段值会在类定义阶段就执行求值,而非等到创建实例时。
在定义TransactionData类时,Python会立刻尝试计算data的默认值pd.read_excel(os.path.join(path_to, file_name)),但此时path_to和file_name只是类的字段声明,还未被赋值(只有创建实例时才会给这两个字段传值),Python找不到这两个变量,直接抛出错误。
另外还有个小问题:if __name__ == "__main__":里的main没加括号,导致程序运行时根本不会执行main函数。
修复方法
最标准的做法是用dataclass的__post_init__方法初始化data字段,这样能在实例创建完成、path_to和file_name已有值时再读取Excel:
import os from dataclasses import dataclass import pandas as pd def main(): df = TransactionData(file_name="transactions.xlsx", path_to="./sources") print(df.data) # 可查看读取的数据 @dataclass class TransactionData: file_name: str path_to: str data: pd.DataFrame = None def __post_init__(self): # 实例创建完成后,用已赋值的字段拼接路径并读取文件 full_path = os.path.join(self.path_to, self.file_name) self.data = pd.read_excel(full_path) if __name__ == "__main__": main() # 这里必须加括号调用函数
如果不想用__post_init__,也可以用field的default_factory封装逻辑,但这种方式不如前者直观:
import os from dataclasses import dataclass, field import pandas as pd def load_data(instance): full_path = os.path.join(instance.path_to, instance.file_name) return pd.read_excel(full_path) def main(): df = TransactionData(file_name="transactions.xlsx", path_to="./sources") @dataclass class TransactionData: file_name: str path_to: str data: pd.DataFrame = field(default_factory=lambda self: load_data(self), init=False)
优先推荐第一种__post_init__的方案,逻辑清晰且易维护。
内容的提问来源于stack exchange,提问作者Asrakh
相关产品推荐
相关产品推荐

