Yar*_*riv 11 python inheritance composition pandas
如何实现组合模式?我有一个Container具有属性对象的类Contained.我想通过简单地调用来重定向/允许访问所有Contained类的方法.我是否以正确的方式做正确的事情?Containermy_container.some_contained_method()
我使用类似的东西:
class Container:
def __init__(self):
self.contained = Contained()
def __getattr__(self, item):
if item in self.__dict__: # some overridden
return self.__dict__[item]
else:
return self.contained.__getattr__(item) # redirection
Run Code Online (Sandbox Code Playgroud)
背景:
我正在尝试构建一个类(Indicator),它增加了现有类(pandas.DataFrame)的功能.Indicator将拥有所有的方法DataFrame.我可以使用继承,但我遵循"赞成组合而不是继承 "的建议(参见例如:python:inheriting或composition中的答案).不继承的一个原因是因为基类不可序列化,我需要序列化.
我发现了这个,但我不确定它是否符合我的需要.
unu*_*tbu 21
注意事项:
DataFrame属性是数字,您可能只想返回该数字.但如果DataFrame属性是DataFrame你可能想要返回一个Container.如果DataFrame属性是a Series或描述符,我们该怎么办?要Container.__getattr__正确实现,您必须为每个属性编写单元测试.__getitem__.__setattr__和__setitem__,__iter__,__len__,等.DataFrames是可选择的,我不确定Container序列化的真正帮助.一些评论:
__getattr__仅在属性不在时才调用self.__dict__.所以你不需要if item in self.__dict__在你的__getattr__.
self.contained.__getattr__(item)调用self.contained的
__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)
Run Code Online (Sandbox Code Playgroud)
这里有一些随机代码来测试 - 至少是表面上 - 是否正确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'>
Run Code Online (Sandbox Code Playgroud)