子类化pd.DataFrame查看数据时触发‘object has no attribute '_data'’错误
这个问题我之前也碰到过!核心原因是你用super().__new__(cls, df)创建实例时,只完成了对象的实例化,但没有触发pandas.DataFrame的初始化逻辑——也就是__init__方法没被调用,导致DataFrame内部的核心属性(比如_data)都没被初始化,所以查看实例时会抛出AttributeError。
修正类方法,正确初始化实例
你不需要直接调用__new__,而是通过cls(df)来创建TestFrame实例,这样会自动调用父类的__init__,完成所有内部属性的初始化,之后再添加自定义属性就没问题了:
import pandas as pd data = pd.DataFrame({'A': [1, 2], 'B': [2, 3], 'C': [4, 5]}) class TestFrame(pd.DataFrame): _metadata = pd.DataFrame._metadata + ["addnl"] @property def _constructor(self): return TestFrame @property def _constructor_sliced(self): return pd.Series @classmethod def plus_one(cls, df): # 用cls()创建实例,触发完整的初始化流程 tf = cls(df) tf.addnl = 1 return tf t1 = TestFrame.plus_one(data) print(t1) # 输出: # A B C # 0 1 2 4 # 1 2 3 5 print(t1.addnl) # 输出: 1
为什么之前的写法不行?
super().__new__(cls, df)只是调用了object.__new__创建了一个空的TestFrame对象,但没有执行DataFrame的初始化逻辑——DataFrame的__init__方法会处理传入的数据,初始化_data、_axes等核心内部属性,这些都是后续操作(比如打印、切片)必须的。你手动调用__new__跳过了这一步,自然会报错。
进阶:自定义__init__方法(如果需要)
如果你想在初始化时直接传入自定义属性,也可以重载__init__,但必须确保调用父类的__init__:
class TestFrame(pd.DataFrame): _metadata = pd.DataFrame._metadata + ["addnl"] @property def _constructor(self): return TestFrame @property def _constructor_sliced(self): return pd.Series def __init__(self, *args, addnl=None, **kwargs): # 先调用父类的初始化方法 super().__init__(*args, **kwargs) # 再设置自定义属性 self.addnl = addnl @classmethod def plus_one(cls, df): # 直接通过构造器传入addnl参数 return cls(df, addnl=1)
这样写的好处是更符合面向对象的设计,而且_metadata里的addnl会确保在你对TestFrame做操作(比如切片、过滤)返回新实例时,这个属性会被自动保留。比如:
t2 = t1[t1['A'] > 1] print(t2.addnl) # 输出: 1,属性被保留了
内容的提问来源于stack exchange,提问作者Chris J Harris
相关产品推荐
相关产品推荐

