如何在Python中重定向包含类的所有方法?

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

注意事项:

  • DataFrames有很多属性.如果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)