15

構成パターンを実装する方法は? Container属性 object を持つクラスがあります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

バックグラウンド:

Indicator既存のクラス ( ) の機能を追加するクラス ( ) を構築しようとしていますpandas.DataFrameIndicatorのすべてのメソッドが含まれDataFrameます。inheritanceを使用することもできますが、「継承よりも構成を優先する」というアドバイスに従っています (たとえば、python: inheriting または compositionの回答を参照してください)。継承しない理由の 1 つは、基本クラスがシリアル化できず、シリアル化する必要があるためです。

私はこれを見つけましが、それが私のニーズに合っているかどうかはわかりません.

4

2 に答える 2

23

警告:

  • DataFrameには多くの属性があります。属性が数値の場合、DataFrameおそらくその数値を返したいだけです。ただし、DataFrame属性がである場合はDataFrame、おそらくを返しますContainerDataFrame属性がSeriesまたは記述子である場合はどうすればよいですか?適切に実装するには、属性ごとにContainer.__getattr__単体テストを作成する必要があります。
  • ユニットテストも必要です__getitem__
  • また、テスト__setattr____setitem__、、、などを定義して単体テストする必要があります。__iter____len__
  • ピクルスはシリアル化の一形態であるため、ピクルス化できる場合、sが実際にシリアル化DataFramesにどのように役立つかはわかりませんContainer

いくつかのコメント:

  • __getattr__属性がにない場合にのみ呼び出されself.__dict__ます。if item in self.__dict__だからあなたはあなたの中に必要はありません__getattr__

  • self.contained.__getattr__(item)self.contained__getattr__メソッドを直接呼び出します。これは、Python属性ルックアップメカニズム全体を回避するため、通常は実行したいことではありません。たとえば、属性が記述子を参照している場合、またはself.contained.__dict____dict__ベースの1つにある可能性を無視します。代わりに。を使用してください。self.contained.__class__itemgetattr(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)

これは、少なくとも表面的にはsに適切に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'>
于 2012-11-19T21:07:07.253 に答える