2017-10-24 9 views
2

*args**kwargsを入力として受け取り、いくつかの変更を加えて元の関数を位置指定して呼び出すデコレータが必要です。修飾された関数からの名前付き引数は変更されません。デコレータの* argsと** kwargsだけを処理し、他の引数をそのまま残す方法

引数の変更は、argsdictkwargsのキーの前に付加するだけです。

など。私はこのように、このデコレータを使用する:ここでpos1pos2named1

from decorator import decorator 

@decorator 
def prepare_opts(decorated_func, *args, **kwargs): 
    prepared_args = prepare_single_opt_keys(args) 
    prepared_kwargs = prepare_named_opt_keys(kwargs) 

    return decorated_func(*prepared_args, **prepared_kwargs) 

@my_decorator 
def func1(pos1, pos2, *args, named1=None, **kwargs): 
    ...do stuff 

をデコレータによって無視されなければなりません。デコレータはpos1{'--named1': 'foobar', '--foo': 'bar'}('--foo', '--bar', '--foo', '--bar')を通過すると、

func1('foo', 'bar', named1='foobar', ('--foo', '--bar'), {'--foo': 'bar'}) 

しかし、これは明らかに動作しないことができます。

だから、このような func1への呼び出しは:

func1('foo', 'bar', 'foo', 'bar', named1='foobar', foo='bar') 

は、このような修飾関数を呼び出す必要があります〜pos2

私は私はデコレータを変更した場合、私は正しい引数を得ることができることを知っている:

@decorator 
def prepare_opts(decorated_func, pos1, pos2, *args, named1, **kwargs): 
    prepared_args = prepare_single_opt_keys(args) 
    prepared_kwargs = prepare_named_opt_keys(kwargs) 

    return decorated_func(pos1, pos2, *prepared_args, named1, **prepared_kwargs) 

しかし、ここで問題がすべて持っていることを、私はデコレータは、異なる機能の多くの仕事をしたいです異なる数の位置および名前付きパラメータ、および追加の*argsおよび**kwargs。私の質問の

概要:は、装飾された機能の位置と名前付き引数のいずれかに触れることなく、私のDecoratorfunctionの*args/**kwargs -Argumentsのものを消費することなくデコレータで*args**kwargsを解析する方法はありますか?

+0

私は本当にこれらの([1](https://stackoverflow.com/questions/147816/preserving-signatures-of-decorated-functions)、[2](https:// stackoverflow。 com/questions/18906760/parsing-args-and-kwargs-in-decorators))はあなたの問題に対する正確な解決策を含んでいますが、少なくとも関連しており、貴重な洞察を提供することができます。特に、少なくとも[decorator'](https://pypi.python.org/pypi/decorator)モジュールをチェックする価値があります。 –

答えて

1

inspect.getargspec機能を試すことができます。私はそれをテストしなかったが、あなたはこのアプローチを使うことができる。

import inspect 

def your_decorator(func): 
    func_args = inspect.getargspec(func)[0] 
    args_number = len(func_args) 

    def wrapper(*args, **kwargs): 
     if len(args) > args_number: 
      args[args_number:] = prepare_single_opt_keys(args[args_number:]) 
     optional_kwargs = {k: kwargs.pop(k) for k in kwargs if k not in func_args} 
     prepared_kwargs = prepare_named_opt_keys(optional_kwargs) 
     kwargs.update(prepared_kwargs) 
     return func(*args, **kwargs) 
    return wrapper 

しかし、私はあなたがそれを必要としないと確信しています。この種のイントロスペクションは、ほとんどの場合避けるべきです。

+0

これを少し修正したものが私にとってはうまくいった。私はまだイントロスペクションを使用することはほとんど避けられないと言っているので、これを行うためのもう1つの "ベストプラクティス"がある場合は、まだ1〜2日待っています。より良いアイデアがポップアップしない場合、私はあなたの答えを受け入れ、私がpython3で動作させるために行った変更を追加します – Igle

+0

私の例ではpy3ではどうなりますか? – Raz

+1

inspectパッケージgetargspecから: '注釈や キーワードのみのパラメータをサポートしていないため、この関数は推奨されていません。どちらかが存在する場合、ValueErrorが発生します。 – Igle

関連する問題