2016-10-07 13 views
6

私が装飾する関数の引数を保持するデコレータを作成しようとしています。これを行う動機はpytest.fixturesとうまくやりとりするデコレータを書くことです。Pythonは関数の引数を保持するデコレータを作成します。

fooがあるとします。単一の引数aが必要です。

def foo(a): 
    pass 

我々がfoo

>>> inspect.getargspec(foo) 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) 

の引数の仕様を取得した場合私たちは頻繁にwrapper機能がwrapped関数にそのままそのすべての引数を渡すデコレータを作成したいです。これを行う最も明白な方法は*args**kwargsです。

def identity_decorator(wrapped): 
    def wrapper(*args, **kwargs): 
     return wrapped(*args, **kwargs) 
    return wrapper 

    def identity_decorator(wrapped): 
    def wrapper(*args, **kwargs): 
     return wrapped(*args, **kwargs) 
    return wrapper 

@identity_decorator 
def foo(a): 
    pass 

これは、当然のことながら、*args**kwargs反射引数仕様と機能を生成します。

>>> inspect.getargspec(foo) 
ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None) 

包まれた機能と一致するか、最初に右引数の仕様と機能を作成するには、引数の仕様を変更するためのいずれかの方法がありますか?

+2

を私は、最近のPythonのバージョンでは、 'functools.wraps'は' inspect.getargspec'と '検査を行うために何かを考えます.signature'はラップされた関数のシグネチャを報告しますが、ラッパーの実際のシグネチャは変更しません。 ['decorator'](https://pypi.python.org/pypi/decorator)サードパーティのライブラリは、私が深く掘り下げたことのない手段で、実際に署名を保存するデコレータ機能を提供します。おそらく、バイトコードの書き換えのようなものを含んでいます。私はそれを使用したことはありません。 – user2357112

+0

多分、http://stackoverflow.com/questions/3729378/how-can-i-programmatically-change-the-argspec-of-a-function-in-a-python-decoratoのようなものをチェックしてください。 – Nf4r

答えて

2

コメントで示唆したように、あなたがdecoratorモジュールを使用することができますかあなたは正しい署名でラムダ関数を作成するためにeval悪の力を使用することができます。

import inspect 

def identity_decorator(wrapped): 
    argspec = inspect.getargspec(wrapped) 
    args = inspect.formatargspec(*argspec) 

    def wrapper(*args, **kwargs): 

     return wrapped(*args, **kwargs) 

    func = eval('lambda %s: wrapper%s' % (args.strip('()'), args), locals()) 

    return func 

@identity_decorator 
def foo(a): 
    pass 

これはちょっとハックですが、それは、関数の引数を保存し:

>>> inspect.getargspec(foo) 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) 
1

私の知る限り、それはSignatureオブジェクトのみのPython 3.3ので可能である。

def identity_decorator(wrapped): 
    def wrapper(*args, **kwargs): 
     return wrapped(*args, **kwargs) 
    wrapper.__signature__ = inspect.signature(wrapped) # the magic is here! 
    return wrapper 

次に、あなたが行うことができます:

@identity_decorator 
def foo(a): 
    pass 

し、最終的に:

>>> inspect.getargspec(foo) 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) 
関連する問題