在自定义类上调用DataFrame时调用特殊函数

时间:2018-03-27 13:55:26

标签: python-3.x pandas oop metaprogramming

我有以下课程:

class Result(UserDict):
    """Implements a especial version of dictionary, that will return the keys 
ordered in the initialized way"""
    def __init__(self, keys_order, items):
        super().__init__(self)
        self.__keys_order = keys_order
        self.data = items

    def __repr__(self):
        attributes = ["{}:{}".format(_stringify(k), _stringify(self.data[k])) for k in self.keys()]
        return "{}".format(", ".join(attributes))

    def keys(self):
        return [key for key in self.__keys_order]


class Results(UserList):
    """Implements a especial kind of list, that has a method to_df"""
    def to_df(self):
        return pd.DataFrame(self.data, columns=self.data[0].keys())

通过这种方式,当我打印Result的实例时,它会以所需的方式显示密钥(由keys_order确定)。此外,类Results实现方法to_df,该方法返回带有按键排序的列的pandas DataFrame

我知道,例如,如果我希望len(results)函数以特殊方式运行,我必须在其中实现__len__方法,以类似的方式,是否可以实现特殊方法,因此当pd.DataFrame(results)实例调用results时,它会调用to_df方法吗?所以我按键排序了列。

1 个答案:

答案 0 :(得分:0)

您可以让您的Result类继承不仅来自UserDict,还来自pd.DataFrame。然后,您只需要将类的_data属性定义为您希望类传递给pd.DataFrame()的内容,即您要构造的pd.DataFrame。

class Result(UserDict, pd.DataFrame):
    """Implements a especial version of dictionary, that will return the keys 
ordered in the initialized way"""
    def __init__(self, keys_order, items):
        super().__init__(self)
        self.__keys_order = keys_order
        self.data = items
        self._data = pd.DataFrame(self.data, columns=self.data[0].keys())

在查看pd.DataFrame类的source code时,这一点很明显:

def __init__(self, data=None, index=None, columns=None, dtype=None,
             copy=False):
    if data is None:
        data = {}
    if dtype is not None:
        dtype = self._validate_dtype(dtype)

    if isinstance(data, DataFrame):
        data = data._data

在调用__init__方法时,这是您在使用pd.DataFrame(results)时实际执行的操作,它将检查结果是否是DataFrame的实例。如果是,则只将数据设置为results._data。或者你的结果类也可以从dict继承,在这种情况下,dict构造函数将在__init__内调用:

    elif isinstance(data, dict):
        mgr = self._init_dict(data, index, columns, dtype=dtype)

这里摘自self._init_dict,将在你的案例中调用:

        else:
            keys = list(data.keys())
            if not isinstance(data, OrderedDict):
                keys = _try_sort(keys)
            columns = data_names = Index(keys)
            arrays = [data[k] for k in keys]

因此,您必须为您的类定义一个keys()方法,该方法返回键(您已经拥有)以及__getitem__,以便最后一行中的数据[k]返回列k的值。