我可以定义如何处理访问python对象(而不仅仅是它的属性)吗?

我可以定义如何处理访问python对象(而不仅仅是它的属性)吗?,python,Python,我在python中有一个自定义类,如果对象本身(即,如果其方法/属性)被访问,我希望以某种方式进行操作 这是一个精心设计的最小工作示例,用来说明我的意思。我有一个类,它保存各种熊猫数据帧s,以便可以单独操作它们: 将熊猫作为pd导入 将numpy作为np导入 类SplitDataFrame: 定义初始化(self,df0,df1): self._dfs=[df0,df1] def增加(自身、数量、公司): self._dfs[num]=self._dfs[num]+inc @财产 def aso

我在python中有一个自定义类,如果对象本身(即,如果其方法/属性)被访问,我希望以某种方式进行操作

这是一个精心设计的最小工作示例,用来说明我的意思。我有一个类,它保存各种
熊猫
数据帧
s,以便可以单独操作它们:

将熊猫作为pd导入
将numpy作为np导入
类SplitDataFrame:
定义初始化(self,df0,df1):
self._dfs=[df0,df1]
def增加(自身、数量、公司):
self._dfs[num]=self._dfs[num]+inc
@财产
def asonedf(自我):
返回pd.concat(自.\u dfs,轴=1)
d=SplitDataFrame(pd.DataFrame(np.random.rand(2,2),columns=['a','b']),
数据帧(np.random.rand(2,2),列=['q','r']))
d、 增加(0,10)
这是可行的,我可以检查
d.\u dfs
现在确实是

[           a          b
 0  10.845681  10.561956
 1  10.036739  10.262282,
           q         r
 0  0.164336  0.412171
 1  0.440800  0.945003]
到目前为止,一切顺利

现在,我想更改/添加类的定义,以便在不使用
.increase
方法时,返回连接的数据帧。换句话说,当访问
d
时,我希望它返回与键入
d.asonedf
时相同的数据帧,即

           a          b         q         r
0  10.143904  10.154455  0.776952  0.247526
1  10.039038  10.619113  0.443737  0.040389
这样,对象就更接近于
pandas.DataFrame
api:

  • 不需要使用
    d.asonedf['a']
    ,我可以访问
    d['a']
  • 不需要使用
    d.asonedf+12
    ,我可以使用
    d+12
  • 等等
可能吗

我可以让
SplitDataFrame
继承
pandas.DataFrame
,但这并不能神奇地添加所需的行为


非常感谢

当然,您可以根据需要将所有相关的magic方法代理到连接的数据帧。如果你不想无休止地重复你自己,你可以动态地这样做

我并不是说这是一条路,但它是可行的:

import textwrap

import pandas as pd
import numpy as np


class SplitDataFrame:
    def __init__(self, df0, df1):
        self._dfs = [df0, df1]

    def increase(self, num, inc):
        self._dfs[num] = self._dfs[num] + inc

    for name in dir(pd.DataFrame):
        if name in (
            "__init__",
            "__new__",
            "__getattribute__",
            "__getattr__",
            "__setattr__",
        ) or not callable(getattr(pd.DataFrame, name)):
            continue
        exec(
            textwrap.dedent(
                f"""
                def {name}(self, *args, **kwargs):
                    return pd.concat(self._dfs, axis=1).{name}(*args, **kwargs)
                """
            )
        )
正如您可能猜到的,这个解决方案附带了各种各样的字符串,它使用了可怕的做法(使用
exec
,使用
dir
,…)


至少我会实现
\uuuu repr\uuuu
,这样你就不会对自己撒谎说这是什么类型的对象,也许你会想显式地枚举你想要定义的所有方法,而不是通过
dir()
获取它们。您可以正常定义函数,然后在类上使用
setattr

“这样,我就可以访问
d['a']
”——而不是通过定义索引操作符
\uu getitem\uuuuu
来实现这一点。您所要求的内容存在各种各样的概念性问题,并且不起作用。感谢@user2357112supportsMonica的评论。是的,我可以为此实现
\uuuuu getitem\uuuuuuu
,我可以为
+12
操作实现
\uuuuuuuu
。但是我不认为包装所有的
pandas.DataFrame
magic方法是一种方法;我想动态创建一个
pandas.DataFrame
,其中所有功能都已经在本地实现。            你能解释一下“各种各样的概念问题”是什么意思吗?你所要求的使你无法从函数返回你的对象,或将你的对象传递给函数,或将你的对象赋给变量,或用它做几乎任何事情。它甚至会破坏您的
increase
方法,因为当
increase
尝试执行
self.\u dfs
,并且数据帧没有
\u dfs
属性时,
self
将自动被数据帧替换。对你的目标做任何事情都几乎是不可能的。我很困惑这个问题与你的目标有什么本质上的区别。同样的问题问起来有点不同吗?“问一个新问题”意味着你可以问一个关于其他事情的全新问题。只是重新问几乎相同的问题并不意味着它!为什么
super
?@user2357112supportsMonica是一个很好的观点,是实验遗留下来的。