Caveats:
- DataFrame 有很多属性。如果一个
DataFrame
属性是一个数字,您可能只想返回该数字。但如果DataFrame
属性是DataFrame
你可能想返回一个Container
。如果DataFrame
属性是一个Series
或描述符?实施Container.__getattr__
正确地说,你真的
必须编写单元测试对于每个属性.
- 还需要进行单元测试
__getitem__
.
- 您还必须定义和单元测试
__setattr__
and __setitem__
, __iter__
, __len__
, etc.
- Pickling 是序列化的一种形式,所以如果
DataFrames
是可腌制的,我不知道如何腌制Container
这对序列化确实有帮助。
一些评论:
__getattr__
仅当属性不在时才被调用self.__dict__
。所以你不需要if item in self.__dict__
在你的__getattr__
.
self.contained.__getattr__(item)
calls self.contained
's
__getattr__
直接方法。这通常不是你想要的
这样做,因为它绕过了整个 Python 属性查找
机制。例如,它忽略了属性的可能性
可能在self.contained.__dict__
,或在__dict__
其中之一的
的基础self.contained.__class__
or if 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
正确并返回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'>