某些操作不遵循Series子类中的自定义属性

时间:2017-09-30 01:39:01

标签: python pandas

根据https://pandas.pydata.org/pandas-docs/stable/internals.html
我应该能够升级熊猫系列

我的MCVE

from pandas import Series


class Xseries(Series):
    _metadata = ['attr']

    @property
    def _constructor(self):
        return Xseries

    def __init__(self, *args, **kwargs):
        self.attr = kwargs.pop('attr', 0)
        super().__init__(*args, **kwargs)

s = Xseries([1, 2, 3], attr=3)

请注意attr属性为:

s.attr

3

然而,当我乘以2

(s * 2).attr

0

这是默认值。因此,attr未被传递。你可能会问,也许这不是预期的行为?我认为这是根据文档https://pandas.pydata.org/pandas-docs/stable/internals.html#define-original-properties

如果我们使用mul方法,它似乎可以正常工作

s.mul(2).attr

3

这不是(与s * 2相同)

s.__mul__(2).attr

0

我想在github上创建一个问题之前把它传递给SO。这是一个错误吗?

有解决方法吗?

我需要能够执行s * 2并将attr属性传递给结果。

2 个答案:

答案 0 :(得分:2)

如果您使用inspect.getsourcelines检查这两个函数mul__mul__的源代码,您会发现它们实际上有不同的实现。

使用s.mul(2).attr仍然无法正常工作,因为它只是使用__finalize__来传播所有属性,但却没有真正地将它们相乘。

或者我可能误解了你的问题而你只想传播而不是繁殖attr

如果是,您可以修改自定义__mul__功能以致电__finalize__

from pandas import Series


class Xseries(Series):
    _metadata = ['attr']

    @property
    def _constructor(self):
        return Xseries

    def __init__(self, *args, **kwargs):
        self.attr = kwargs.pop('attr', 0)
        super().__init__(*args, **kwargs)

    def __mul__(self, other):
        internal_result = super().__mul__(other)
        return internal_result.__finalize__(self)

s = Xseries([1, 2, 3], attr=3)

如果没有,您可以手动乘以attr并返回。

from pandas import Series


class Xseries(Series):
    _metadata = ['attr']

    @property
    def _constructor(self):
        return Xseries

    def __init__(self, *args, **kwargs):
        self.attr = kwargs.pop('attr', 0)
        super().__init__(*args, **kwargs)

    def __mul__(self, other):
        internal_result = super().__mul__(other)
        if hasattr(other, "attr"):
            internal_result.attr = self.attr * other.attr
        else:
            internal_result.attr = self.attr * other
        return internal_result

s = Xseries([1, 2, 3], attr=3)

答案 1 :(得分:0)

如果@chrisb发布了类似的答案,我会删除这个答案。

由@chrisb here发布,这是一个悬而未决的问题。

Matthiasha发布了一个workaround,使用我在问题中的示例在下面重新创建。{/ p>

from pandas import Series


class Xseries(Series):
    _metadata = ['attr']

    @property
    def _constructor(self):
        def _c(*args, **kwargs):
            # workaround for https://github.com/pandas-dev/pandas/issues/13208
            return Xseries(*args, **kwargs).__finalize__(self)
        return _c

    def __init__(self, *args, **kwargs):
        self.attr = kwargs.pop('attr', 0)
        super().__init__(*args, **kwargs)

现在问题解决了:

(Xseries([1, 2, 3], attr=3) * 2).attr

3