如何判断__init__()是否由方法调用触发?附类设计示例
子类化pandas.Series时__init__意外触发的问题分析
最近我碰到一个挺迷惑的情况:自定义的TSeries类(继承自pd.Series)里的__init__()方法,明显是被某个方法调用触发的,但一开始我完全摸不着头绪。后来仔细琢磨了下,推测这大概率和pandas内部返回对象副本的机制有关。
先给大家看看这个类的设计示例:
import copy import pandas as pd class TSeries(pd.Series): # 用来标记需要保留的自定义属性 _metadata = ['some_new_attr'] def __init__(self, *args, **kwargs): # 必须做复制操作,不然很容易意外修改pd.Series、TSeries这类可变参数的内容 super().__init__(*args, **kwargs) # 举个例子,对自定义属性做深拷贝,避免引用共享 if 'some_new_attr' in kwargs: self.some_new_attr = copy.deepcopy(kwargs['some_new_attr'])
为什么__init__会被意外触发?
- 熟悉pandas内部机制的话就知道,很多内置方法(比如
head()、sum()这类返回新对象的操作)在生成子类实例时,会调用子类的__init__方法来构建副本。这不像我们手动创建实例那样直观,所以很容易让人觉得“怎么突然触发了__init__”。 - 你遇到的情况,几乎可以肯定是pandas在处理对象复制/转换时,调用了
TSeries的构造方法,而不是直接用底层的实例创建逻辑。
关于复制操作的必要性
- 如果不在
__init__里做深拷贝,当传入的参数是可变类型(比如列表、字典)时,多个实例会共享同一个引用。这就导致你修改其中一个实例的属性时,原对象或者其他关联实例的内容也会被意外改动,踩过这个坑的人都懂有多头疼。 - 另外,
_metadata这个列表一定要配置对,它是pandas识别自定义属性的关键,确保这些属性在对象的复制、序列化、方法链式调用中能被正确保留下来。
内容的提问来源于stack exchange,提问作者Brad Solomon
相关产品推荐
相关产品推荐

