注意事项:
- DataFrames 有很多属性。如果
DataFrame
属性是数字,您可能只想返回该数字。但是如果DataFrame
属性是DataFrame
你可能想要返回一个Container
. 如果DataFrame
属性是一个Series
或一个描述符,我们应该怎么做?要Container.__getattr__
正确实现,您确实必须为每个属性编写单元测试。
- 还需要进行单元测试
__getitem__
。
- 您还必须定义和单元测试
__setattr__
and __setitem__
, __iter__
,__len__
等。
- Pickling 是序列化的一种形式,所以如果
DataFrames
是可腌制的,我不确定Container
s 如何真正帮助序列化。
一些评论:
__getattr__
仅当属性不在 中时才调用self.__dict__
。所以你不需要if item in self.__dict__
在你的__getattr__
.
self.contained.__getattr__(item)
直接调用self.contained
's
__getattr__
方法。这通常不是您想要做的,因为它绕过了整个 Python 属性查找机制。例如,它忽略了该属性可能位于self.contained.__dict__
或位于__dict__
的基数之一中的可能性,self.contained.__class__
或者如果item
指代描述符。而是使用getattr(self.contained, item)
.
import pandas
import numpy as np
def tocontainer(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return Container(result)
return wrapper
class Container(object):
def __init__(self, df):
self.contained = df
def __getitem__(self, item):
result = self.contained[item]
if isinstance(result, type(self.contained)):
result = Container(result)
return result
def __getattr__(self, item):
result = getattr(self.contained, item)
if callable(result):
result = tocontainer(result)
return result
def __repr__(self):
return repr(self.contained)
下面是一些随机代码,用于测试是否——至少在表面上——正确地Container
委托给DataFrame
s 并返回Containers
:
df = pandas.DataFrame(
[(1, 2), (1, 3), (1, 4), (2, 1),(2,2,)], columns=['col1', 'col2'])
df = Container(df)
df['col1'][3] = 0
print(df)
# col1 col2
# 0 1 2
# 1 1 3
# 2 1 4
# 3 2 1
# 4 2 2
gp = df.groupby('col1').aggregate(np.count_nonzero)
print(gp)
# col2
# col1
# 1 3
# 2 2
print(type(gp))
# <class '__main__.Container'>
print(type(gp[gp.col2 > 2]))
# <class '__main__.Container'>
tf = gp[gp.col2 > 2].reset_index()
print(type(tf))
# <class '__main__.Container'>
result = df[df.col1 == tf.col1]
print(type(result))
# <class '__main__.Container'>