作成されたすべての関数が空のクラスをクローンするにはどうすればよいですか

デフォルトで None に設定されている引数 p を取る関数 f があるとします:

def f(p = None): ...

p が指定されている場合、特定のメンバー関数を持つクラス C のオブジェクトであることが期待されます。これにより、次のようなコードが繰り返されます

p が None でない場合: p.f()

これは面倒でエラーが発生しやすい作業です。 p のデフォルトとして None を選択する代わりに、すべてのメンバ関数が何もしない C のクローンが必要です。その後、次のように記述できます

def f(p = Cc()):
p.f()
...

CcC のクローンです。
p が複製されたクラスのオブジェクトである場合、呼び出しは何もしません。p が呼び出し元によって提供されている場合、対応する f が呼び出されます。
このようなクローンを自動的に作成するにはどうすればよいでしょうか?

この問題は、次のようなデコレータ クラスを定義することで解決できます:

import inspect

クラスMockDec:
def __init__(自己、ベース):
self.base_func_names = {v[0] for v in inspect.getmembers(base, predicate=inspect.isfunction)
そうでない場合 v[0].startswith('__')}

def __call__(self, cls):
def pss(*argc, **argv):
合格
cls_func_names = {v[0] for v in inspect.getmembers(cls, predicate=inspect.isfunction)
そうでない場合 v[0].startswith('__')}
for n in self.base_func_names - cls_func_names:
setattr(cls、n、pss)
cls を返す

ここで base_func_namescls_func_names は、basecls で定義されたすべての関数名を含む Python セットです。 for ループ関数が cls に追加され、これらが pss を呼び出すだけで、何もしません。式 self.base_func_names - cls_func_names は設定の違いです。したがって、base で定義された関数は、cls で定義されていない場合にのみ cls に追加されます。

デコレータの使用例を次に示します。最初にクラス C1 を定義します:

クラス C1:
def __init__(自己):
print( "C1.__init__" )

def f1(自己、私):
print( f"C1.f1({i})" )

def f2(自己、私):
print( f"C1.f2({i})" )

MockDec を使用して C1 のクローンを作成します:

@MockDec(base=C1)
クラス C2:
def __init__(自己):
print( "C2.__init__" )

def f2(自己、私):
print( f"C2.f2({i})" )

c1 = C1()
c1.f1(7)
c1.f2(9)

c2 = C2()
c2.f1(ナンセンス="無") #1
c2.f2(19) #2

これにより出力が得られます

C1.__init__
C1.f1(7)
C1.f2(9)
C2.__init__
C2.f2(19)

明らかに、C2#1 で呼び出されたときに何もしない関数 f1 を提供します。 #2 に示すように、f2 の定義はデコレータによって変更されません。