1
1

More than 1 year has passed since last update.

pythonで親クラスの任意のメソッド実行前後に特定の処理を行う方法

Posted at

背景.

例えば、「テーブルはレコードのリストであり、レコードは辞書(連想配列)である」(=テーブルとは辞書のリストである)という考え方に基づいてTable型を作るとしよう。
この考え方に基づいて早速

class Table(list):
    def __init__(self, columns):
        self.__columns = columns
    def to_excel(self): ...
    def to_pd_df(self): ...
    def to_numpy(self): ...

    @classmethod
    def from_excel(Table, excel_path): ...
    @classmethod
    def from_pd_df(Table, df): ...
    @classmethod
    def from_numpy(Table, arr2d): ...

と書いたとする。
後はlistと同じように辞書をappend, clear, pop等、リストに対するすべての操作が利用可能である。
(なのでリスト内法表記などを用いてテーブルを自由自在にフィルタ出来るというわけだ)

ところで、append, += など、任意の操作をした際に、「中身がすべて辞書dであって、かつset(d.keys())set(self.__columns)と一致するか」の検査を行いたいとしよう。

この場合はどうしたらよいか。

解決.

class Table(list):
    def __getattribute__(self, method_name):
        if hasattr(list, method_name): # 親クラスで定義されたメソッドの場合
            def closure(*a, **ka):
                # 親メソッド呼び出し前の処理をここにかく
                rtn = object.__getattribute__(self, method_name) # 親メソッド呼び出し
                self.__raise_error_if_illegal_component_found() # 親メソッド呼び出し後の処理をここに書く
                return rtn
            return closure
        # 親クラスにないメソッドの場合
        return object.__getattribute__(self, method_name)

    def ...

__getattr__の場合は「存在しないメンバを参照されたときに動く」のに対し、
__getattribute__は「メンバの存在の有無にかかわらず直ちに呼び出される」強力なものとなっている。
そのため、__getattribute__内でself.hogeのように自オブジェクトのメンバを呼ぼうものなら、(再帰処理などを意図して書いた者でない限り)無限ループに陥ってしまう。
この無限ループを回避するために、object.__getattribute__を利用する。
「自クラスの__getattribute__とは別物だから循環参照にならない」というわけだ。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1