在属性的属性更改时触发操作

发布于 2025-01-09 16:54:01 字数 1296 浏览 1 评论 0原文

我有一个名为 Data 的对象,它有一个 pandas DataFrame (df) 作为属性。我想要做的是在 df 的更改上触发操作。具体来说,添加一个新列。

现在我通过重新设置属性来使其工作,但它没有捕获其属性的任何更改。这是一个示例:

class Data:
    def __init__(self, df: Optional[DataFrame] = None) -> None:
        self.sets = 0
        self.updates = 0
        self._df = df if df is not None else pd.DataFrame

    @property
    def df(self) -> DataFrame:
        return self._df

    @df.setter
    def df(self, new_df: DataFrame) -> None:
        if self._df.empty:
            self.sets += 1
            # do something...
        else:
            self.updates += 1
            # do somthing else...
        self._df = new_df.copy(deep=True)

行为

初始化

d = Data()
# d.sets == 0
# d.updates == 0

设置df

d.df = pd.DataFrame({
    'a': [1, 1, 1],
    'b': [2, 2, 2],
})
# d.sets == 1
# d.updates == 0

更新df

d.df = pd.DataFrame({
    'a': [1, 1, 1],
    'b': [2, 2, 2],
    'c': [3, 3, 3],
})
# d.sets == 1
# d.updates == 1

添加新列(不工作)

d.df['d'] = [4, 4, 4]
# d.sets == 1
# d.updates == 1 (EXPECTED 2)

I have an object called Data, which has a pandas DataFrame (df) as an attribute. What I want to do is trigger an action on the change of that df. Specifically, the addition of a new column.

Right now I have it working by re-setting the attribute, but it doesn't catch any changes to its attributes. Here is an example:

class Data:
    def __init__(self, df: Optional[DataFrame] = None) -> None:
        self.sets = 0
        self.updates = 0
        self._df = df if df is not None else pd.DataFrame

    @property
    def df(self) -> DataFrame:
        return self._df

    @df.setter
    def df(self, new_df: DataFrame) -> None:
        if self._df.empty:
            self.sets += 1
            # do something...
        else:
            self.updates += 1
            # do somthing else...
        self._df = new_df.copy(deep=True)

Behavior

Init

d = Data()
# d.sets == 0
# d.updates == 0

Set df

d.df = pd.DataFrame({
    'a': [1, 1, 1],
    'b': [2, 2, 2],
})
# d.sets == 1
# d.updates == 0

Update df

d.df = pd.DataFrame({
    'a': [1, 1, 1],
    'b': [2, 2, 2],
    'c': [3, 3, 3],
})
# d.sets == 1
# d.updates == 1

Add New Column (NOT WORKING)

d.df['d'] = [4, 4, 4]
# d.sets == 1
# d.updates == 1 (EXPECTED 2)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笑梦风尘 2025-01-16 16:54:01

一种方法是定义一个辅助方法来获取集合和更新计数,而不是直接访问属性,如下所示

from typing import Optional

import pandas as pd
from pandas.testing import assert_frame_equal


class Data:
    def __init__(self, df: Optional[pd.DataFrame] = None) -> None:
        self.sets = 0
        self.updates = 0
        self._df = df or pd.DataFrame  # you don't need an if/else expression
        self.previous = self._df  # new attribute to track last known _df

    @property
    def df(self) -> pd.DataFrame:
        return self._df

    @df.setter
    def df(self, new_df: pd.DataFrame) -> None:
        if self._df.empty:
            self.sets += 1
            # do something...
        else:
            self.updates += 1
            # do somthing else...
        self._df = new_df.copy(deep=True)
        self.previous = new_df.copy(deep=True)

    @property
    def count_changes(self) -> dict[str, int]:
        # check if _df has been modified
        try:
            assert_frame_equal(self._df, self.previous)
        except AssertionError:
            self.updates += 1
        return {"sets": self.sets, "updates": self.updates}

d = Data()
d.df = pd.DataFrame(
    {
        "a": [1, 1, 1],
        "b": [2, 2, 2],
    }
)
d.df = pd.DataFrame(
    {
        "a": [1, 1, 1],
        "b": [2, 2, 2],
        "c": [3, 3, 3],
    }
)
d.df["d"] = [4, 4, 4]

print(d.count_changes)
# Output
{'sets': 1, 'updates': 2}  # as expected

One way to do it is to define a helper method to get both sets and updates count instead of accessing attributes directly, like this:

from typing import Optional

import pandas as pd
from pandas.testing import assert_frame_equal


class Data:
    def __init__(self, df: Optional[pd.DataFrame] = None) -> None:
        self.sets = 0
        self.updates = 0
        self._df = df or pd.DataFrame  # you don't need an if/else expression
        self.previous = self._df  # new attribute to track last known _df

    @property
    def df(self) -> pd.DataFrame:
        return self._df

    @df.setter
    def df(self, new_df: pd.DataFrame) -> None:
        if self._df.empty:
            self.sets += 1
            # do something...
        else:
            self.updates += 1
            # do somthing else...
        self._df = new_df.copy(deep=True)
        self.previous = new_df.copy(deep=True)

    @property
    def count_changes(self) -> dict[str, int]:
        # check if _df has been modified
        try:
            assert_frame_equal(self._df, self.previous)
        except AssertionError:
            self.updates += 1
        return {"sets": self.sets, "updates": self.updates}

So that:

d = Data()
d.df = pd.DataFrame(
    {
        "a": [1, 1, 1],
        "b": [2, 2, 2],
    }
)
d.df = pd.DataFrame(
    {
        "a": [1, 1, 1],
        "b": [2, 2, 2],
        "c": [3, 3, 3],
    }
)
d.df["d"] = [4, 4, 4]

print(d.count_changes)
# Output
{'sets': 1, 'updates': 2}  # as expected
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文