例如,如果我围绕pandas数据框创建一个简单的包装器:
from pandas import DataFrame
class MyDataFrame(DataFrame):
def __init__(self,data):
DataFrame.__init__(self,data)
@staticmethod
def add(a, b):
return a + b
然后我实例化它..
x = MyDataFrame([1,2,3])
x.add(1,2)
# => 3
type(x)
# => __main__.MyDataFrame
它有效。但是,如果我在其上调用一个返回数据帧的数据帧方法,那么它就不是我的包装类的实例。
y = x.reindex([3,4,5])
type(y)
# => pandas.core.frame.DataFrame
如何让它为所有DataFrame方法返回MyDataFrame的实例?这是一个常见的问题吗?我是以错误的方式接近这个吗?
答案 0 :(得分:2)
您展示的示例不是包装器,而是Python中的子类。现在,python子类和方法解析在你的情况下通过简单的规则行事
type
。 所以,在你的情况下,
x
被定义为类MyDataFrame
的对象 - 简单。显然,根据定义,type(x)
为MyDataFrame
。add
期间,它会查看接收器对象,即x
类的MyDataFrame
。实际上,这个类定义了方法add
。所以,它只返回该方法的结果,奇怪的是,尝试调用DataFrame([1, 2, 3]).add(1, 2)
。结果会有所不同,因为它会查看add
类中定义的pandas.DataFrame
方法。reindex
中未定义MyDataFrame
。我们下一步应该去哪儿?类层次结构,表示pandas.DataFrame
。现在reindex
确实由此类定义,它返回一个pandas.DataFrame对象!。 (见http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.reindex.html#pandas.DataFrame.reindex)所以,难怪y
是pandas DataFrame
。现在,我首先要通过扩展pandas DataFrame来了解你的工作。像这样扩展不是常见的做法。如果您提供了您想要做的详细信息,我们可以提供解决方案。
编辑:您的原始问题与扩展方法或扩展对象有关(C#有它们,正如您正确指出的那样,JS原型为您提供相同的功能.Python没有扩展方法/对象作为一等成员。已经就此进行了讨论。例如python extension methods)
答案 1 :(得分:0)
在Pandas中有几个案例,这些类没有很好地实现,以形成派生类的基础。其中一些问题已得到修复,例如https://github.com/pydata/pandas/pull/4271和https://github.com/pydata/pandas/issues/60。
可以实现父reindex
方法,因此结果是子子类:
from pandas import DataFrame
class DF():
def __init__(self, data):
print('DF __init__')
self.data = data
def reindex(self, index):
print('DF reindex')
return self.__class__(self.data)
# return DF(self.data) # not like this!
class MyDF(DF):
def __init__(self, data):
DF.__init__(self, data)
@staticmethod
def add(a, b):
return a + b
x = MyDF([1,2,3])
x.add(1,2)
# => 3
type(x)
y = x.reindex([3,4,5])
type(y)
z = DF([1,2,3])
type(z.reindex([1, 2]))
在较新版本的Pandas中,`_constructor'在内部设置以控制返回的类型。设置此类属性似乎可以解决问题:
class MyDataFrame(DataFrame):
def __init__(self, *args, **kwargs):
DataFrame.__init__(self, *args, **kwargs)
@staticmethod
def add(a, b):
return a + b
MyDataFrame._constructor = MyDataFrame
>>> type(y)
<class '__main__.MyDataFrame'>