私は、ETL(データ移動)ワークフローのフレームワークであるpetlと呼ばれるパッケージから別のクラスをラップ/装飾/拡張するPythonクラスを作成しています。設計上の制約のため、サブクラス化することはできません。返されるオブジェクトの種類を制御できるように、すべてのメソッド呼び出しは自分のクラスを介して送信する必要があります。したがって、原則としてこれはプロキシクラスですが、既存の回答/レシピを使用するのに問題があります。これは私のコードがどのように見えるかです:
from functools import partial
class PetlTable(object):
"""not really how we construct petl tables, but for illustrative purposes"""
def hello(name):
print('Hello, {}!'.format(name)
class DatumTable(object):
def __init__(self, petl_tbl):
self.petl_tbl = petl_tbl
def __getattr__(self, name):
"""this returns a partial referencing the child method"""
petl_attr = getattr(self.petl_tbl, name, None)
if petl_attr and callable(petl_attr):
return partial(self.call_petl_method, func=petl_attr)
raise NotImplementedError('Not implemented')
def call_petl_method(self, func, *args, **kwargs):
func(*args, **kwargs)
次に、テーブルをインスタンス化して何かを呼び出そうとします。
# create a petl table
pt = PetlTable()
# wrap it with our own class
dt = DatumTable(pt)
# try to run the petl method
dt.hello('world')
これにより、が得られますTypeError: call_petl_method() got multiple values for argument 'func'
。
これは、位置引数でのみ発生します。kwargsは問題ないようです。私はそれがself
渡されないことに関係しているとかなり確信していますが、解決策が何であるかはわかりません。誰かが私が間違っていること、または完全に良い解決策を考えることができますか?
これは、位置引数とキーワード引数の混合に関する一般的な問題のようです。TypeError:引数に複数の値を取得しました
それを回避するために、私は位置引数をfunc
取り出してcall_petl_method
、子関数のkwargと重複する可能性が低いkwargに配置しました。少しハッキーですが、動作します。
私Proxy
はこれらすべてを一般的に行うためのクラスを書くことになりました:
class Proxy(object):
def __init__(self, child):
self.child = child
def __getattr__(self, name):
child_attr = getattr(self.child, name)
return partial(self.call_child_method, __child_fn__=child_attr)
@classmethod
def call_child_method(cls, *args, **kwargs):
"""
This calls a method on the child object and wraps the response as an
object of its own class.
Takes a kwarg `__child_fn__` which points to a method on the child
object.
Note: this can't take any positional args or they get clobbered by the
keyword args we're trying to pass to the child. See:
https://stackoverflow.com/questions/21764770/typeerror-got-multiple-values-for-argument
"""
# get child method
fn = kwargs.pop('__child_fn__')
# call the child method
r = fn(*args, **kwargs)
# wrap the response as an object of the same class
r_wrapped = cls(r)
return r_wrapped
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加