如何重定向Python中包含的类的所有方法?
如何实现组合模式?我有一个类如何重定向Python中包含的类的所有方法?,python,inheritance,pandas,composition,Python,Inheritance,Pandas,Composition,如何实现组合模式?我有一个类容器,其中包含一个属性对象。我想通过调用my\u Container.some\u Contained\u method()从Container重定向/允许访问Contained类的所有方法。我是否以正确的方式做正确的事情 我用的是: class Container: def __init__(self): self.contained = Contained() def __getattr__(self, item): if
容器
,其中包含一个属性对象
。我想通过调用my\u Container.some\u Contained\u method()
从Container
重定向/允许访问Contained
类的所有方法。我是否以正确的方式做正确的事情
我用的是:
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
背景:
我正在尝试构建一个类(Indicator
),它添加到现有类(pandas.DataFrame
)的功能中<代码>指示器将具有数据帧的所有方法。我可以使用继承,但我遵循“偏好组合而非继承”的建议(例如,请参见:)中的答案。不继承的一个原因是基类不可序列化,我需要序列化
我已经找到了,但我不确定它是否适合我的需要。注意事项:
- 数据帧有很多属性。如果
属性是一个数字,您可能只想返回该数字。但是如果DataFrame
属性是DataFrame
,则可能需要返回一个DataFrame
容器。如果
属性是DataFrame
或描述符,我们应该怎么做?要正确地实现Series
,您真的需要 必须为每个属性编写单元测试容器。\uuu getattr\uuuu
也需要进行单元测试\uuu getitem\uu
- 您还必须定义和单元测试
和\uuuuuu setattr\uuuuuu
,\uuuuuuu setitem\uuuuuuuuu
,等等\uuuuuu iter\uuuuuuuuuuuuu
- pickle是序列化的一种形式,因此如果
是可pickle的,我不确定数据帧
对序列化有什么帮助容器
仅当属性不在\uuuu getattr\uuuu
中时才会调用。因此,您不需要在您的self.\uuuu dict\uuuu
中使用self中的\uu getattr\uuuu
项
调用self.contained.\uuu getattr\uuuuuuuuuuuuuuuuuuuuuuuuuuu(项目)
self.contained
方法。这通常不是你想要的 因为它绕过了整个Python属性查找 机制。例如,它忽略了属性 可以是独立的,也可以是其中一个的\uuuu getattr\uuuu
或如果自包含的基础。\uuuuu类\uuuuu
指的是 描述符。而是使用项
getattr(自包含项)
下面是一些随机代码,用于测试--(至少表面上--
容器
是否正确地委托到数据帧
并返回容器
:
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'>
df=pandas.DataFrame(
[(1,2)、(1,3)、(1,4)、(2,1)、(2,2,)],列=['col1','col2'])
df=集装箱(df)
df['col1'][3]=0
打印(df)
#col1 col2
# 0 1 2
# 1 1 3
# 2 1 4
# 3 2 1
# 4 2 2
gp=df.groupby('col1')。聚合(np.count\u非零)
打印(总成)
#可乐
#可乐
# 1 3
# 2 2
打印(类型(gp))
#
打印(类型(gp[gp.col2>2]))
#
tf=gp[gp.col2>2].reset_index()
打印(类型(tf))
#
结果=df[df.col1==tf.col1]
打印(打印(结果))
#
我发现unbutbu的答案对我自己的应用程序非常有用,我在jupyter笔记本中正确显示它时遇到了问题。我发现向类中添加以下方法解决了这个问题
def _repr_html_(self):
return self.contained._repr_html_()
def _repr_latex_(self):
return self.contained._repr_latex_()
代理对象将如何帮助您的序列化-您仍然需要以某种方式这样做。。。只需从基础继承(因为您的对象“是-a”)并从那里开始工作…a
pandas.DataFrame
有许多方法返回另一个DataFrame
。可能很难安排您的容器
返回另一个容器
。@Jon基类不是serializalbe,而是pickable。扩展组件的酸洗比扩展超类的酸洗更容易。@unutbu,很好。我想我可以包装每个返回的数据帧
。你能解释一下为什么这比继承更可取(或不可取)吗?这非常有用。我在其他地方找不到关于这个的好讨论。@user1579844:如果类B通过添加新方法扩展了类a,并且没有覆盖类a的方法,那么使用继承。如果在使用A
的地方可以替换B
,则使用继承。将组合用于依赖项注入(允许类B
具有类A2
,而不是类a
)。有关此想法和其他想法,请参阅。有时组合或继承都不对——有时一个简单的函数是最好的。(我很想知道这里是否是这样。)@unutbu,如果我选择简单的函数解决方案,我如何定制myindicator.plot(),例如@user1579844:您将def myplot(dataframe):…
定义为模块级函数。
def _repr_html_(self):
return self.contained._repr_html_()
def _repr_latex_(self):
return self.contained._repr_latex_()