デコレータから関数のサブ関数をオーバーライドしますか?

nowox

barデコレータを使用して動的に作成したいこのコードについて考えてみましょう。

def foo():
   def bar():
      print "I am bar from foo"
   print bar()

def baz():
   def bar():
      print "I am bar from baz"
   print bar()

デコレータを使って外側からバーを作成できると思いました。

def bar2():
   print "I am super bar from foo"

setattr(foo, 'bar', bar2)

しかし、結果は私が期待していたものではありません(私は取得したいI am super bar from foo

>>> foo()
I am bar from foo

デコレータで既存の関数のサブ関数をオーバーライドすることは可能ですか?

実際の使用例

私はライブラリのラッパーを書いています。ボイラープレートコードを避けるために、作業を簡素化したいと思います。

各ライブラリ関数にはプレフィックスがlib_あり、エラーコードを返します。現在の関数にプレフィックスを追加して、エラーコードを処理したいと思います。これはこれと同じくらい簡単かもしれません:

def call():
   fname = __libprefix__ + inspect.stack()[1][3]   
   return_code = getattr(__lib__, fname)(*args)
   if return_code < 0: raise LibError(fname, return_code)

def foo():
   call()

問題は、特定の場合に呼び出しの動作が異なる可能性があることです。一部のライブラリ関数はerror_codeを返さないため、次のように記述する方が簡単です。

def foo():
   call(check_status=True)

または私の意見でははるかに良いです(これは私がデコレータについて考え始めたポイントです):

@LibFunc(check_status=True)
def foo():
   call()

この最後の例では、デコレータ自体によって動的に作成されたサブ関数としてcall内部foo宣言する必要があります。

アイデアは次のようなものを使用することでした:

class LibFunc(object):
    def __init__(self,**kwargs):
        self.kwargs = kwargs

    def __call__(self, original_func):
        decorator_self = self
        def wrappee( *args, **kwargs):
            def call(*args):
                fname = __libprefix__ + original_func.__name__
                return_code = getattr(__lib__, fname)(*args)
                if return_code < 0: raise LibError(fname, return_code)
            print original_func
            print call

            # <<<< The part that does not work
            setattr(original_func, 'call', call) 
            # <<<<

            original_func(*args,**kwargs)
            
        return wrappee

最初はcall、書き込みを最小限に抑えるために、デコレータ自体内部を呼び出したくなりました。

@LibFunc():
foo(): pass

残念ながら、これはオプションではありません。他のことをcall:の前後に行う必要があるためです。

@LibFunc():
foo(a,b): 
   value = c_float()
   call(a, pointer(value), b)
   return value.value

私が考えたもう1つのオプションはを使用することSWIGでしたが、SWIGラッピング関数を使用して既存のライブラリを再構築する必要があるため、これもオプションではありません。

最後になりましたが、SWIGタイプマップからインスピレーションを得て、ラッパーを次のように宣言する場合があります

@LibFunc(check_exit = true, map = ('<a', '>c_float', '<c_int(b)')):
foo(a,b): pass

これは私にとって最善の解決策のように見えますが、これは別のトピックであり、別の質問です...

ケビンJ.チェイス

あなたはデコレータのアイデアと結婚していますか?あなたの目標がそれぞれがラップするモジュールレベルの関数の束である場合、somelib.lib_somefunctionnameなぜそれが必要なのかわかりません。

これらのモジュールレベルの名前は関数である必要はなく、呼び出し可能である必要があります。それらが__call__メソッドを持っている限り、それらはクラスインスタンスの束である可能性があります

2つの異なるサブクラスを使用して、戻り値の処理方法を決定しました。

#!/usr/bin/env python3


import libtowrap  # Replace with the real library name.


class Wrapper(object):
    '''
    Parent class for all wrapped functions in libtowrap.
    '''

    def __init__(self, name):
        self.__name__ = str(name)
        self.wrapped_name = 'lib_' + self.__name__
        self.wrapped_func = getattr(libtowrap, self.wrapped_name)
        self.__doc__ = self.wrapped_func.__doc__
        return


class CheckedWrapper(Wrapper):
    '''
    Wraps functions in libtowrap that return an error code that must
    be checked.  Negative return values indicate an error, and will
    raise a LibError.  Successful calls return None.
    '''

    def __call__(self, *args, **kwargs):
        error_code = self.wrapped_func(*args, **kwargs)
        if error_code < 0:
            raise LibError(self.__name__, error_code)
        return


class UncheckedWrapper(Wrapper):
    '''
    Wraps functions in libtowrap that return a useful value, as
    opposed to an error code.
    '''

    def __call__(self, *args, **kwargs):
        return self.wrapped_func(*args, **kwargs)


strict = CheckedWrapper('strict')
negative_means_failure = CheckedWrapper('negative_means_failure')
whatever = UncheckedWrapper('whatever')
negative_is_ok = UncheckedWrapper('negative_is_ok')

モジュールのインポート中にラッパーの「関数」が割り当てられることに注意してください。それらはトップレベルのモジュール名前空間にありテストによって隠されていませんif __name__ == '__main__'

ほとんどの目的で関数のように動作しますが、わずかな違いがあります。たとえば、各インスタンスに、__name__割り当てられている名前に一致するaを指定しましたが、...でlib_使用されているプレフィックス名ではありませんがlibtowrap、元のをコピーしました__doc__。これは、のようなプレフィックス名を参照している可能性がありますlib_some_other_functionまた、それらをテストすると、isinstanceおそらく人々を驚かせるでしょう。

デコレータについての詳細、および用のために多くの私は上記のもののようなより多くの迷惑少し矛盾、グラハムDumpletonの半時間の講義「を参照してください。デコレータを作成するための高度な方法」(PyCon米国2014 ;スライド)。彼はwraptモジュール(Python Package Index ; Git Hub ; Read the Docs)の作成者であり、通常のデコレータの不整合をすべて(?)修正します。それはあなたの問題を完全に解決するかもしれません(にlib_現れる古いスタイルの名前を除いて__doc__)。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

別のライブラリからの関数の戻り値をオーバーライドします

分類Dev

AngularJS-オーバーライドディレクティブのコンパイル関数はリンク関数を呼び出しませんか?

分類Dev

サブクラスから親関数をオーバーライドする方法がわかりません

分類Dev

Javascript関数をオーバーライドしますか?

分類Dev

JQuery関数をオーバーライドします(ロギングデコレータ)

分類Dev

関数は基本関数をオーバーライドしますか?

分類Dev

ディレクティブでコントローラー関数をオーバーライドするのは良い考えですか?

分類Dev

ディレクティブのリンク関数をオーバーライドします

分類Dev

Pythonデコレータオーバーライド関数の引数

分類Dev

トレイト関数をオーバーライドし、オーバーライドされた関数から呼び出す方法は?

分類Dev

サブクラスが基本クラスの仮想関数をオーバーライドするかどうかをテストします

分類Dev

noexcept(false)デストラクタは、すべての特殊メンバー関数の例外仕様をオーバーライドしますか?

分類Dev

PouchDBコールバック関数からデータを取得しますか?

分類Dev

JavaコードからウェブサイトのJavaScript関数を呼び出しますか?

分類Dev

クラスメンバー関数のアドレスを取得し、ポインターから呼び出す

分類Dev

JSONPコールバック関数からAngularコントローラーにデータを渡します

分類Dev

トレイト内のオブジェクト内の関数をオーバーライドします

分類Dev

JavaScript関数オブジェクトをオーバーライドしてすべての関数呼び出しをログに記録できますか?

分類Dev

サブタイプのオーバーロードで関数を構成することは可能ですか?

分類Dev

メンバー関数のオーバーロードのために可変個引数テンプレートクラスから型を抽出します

分類Dev

ライブラリからの関数のオーバーロード

分類Dev

const関数をオーバーライドしてC ++のクラス変数を変更しますか?

分類Dev

ローカル変数angular6のサブスクライブ関数からデータを取得します

分類Dev

javascriptのtoString関数をオーバーライドします

分類Dev

Rの関数を使用してサーバーからデータをダウンロードするときにforループを利用しますか?

分類Dev

配列内のオブジェクトからオーバーライド関数を呼び出すAngelscript

分類Dev

Typescriptの親クラスのコンストラクターからサブクラスのメンバー関数をトリガーできますか?

分類Dev

複数の関連レコードlaravelから関連レコードのセットを取得しますか?

分類Dev

サブクラスが仮想関数をオーバーライドするのに、親クラスのデフォルト関数パラメーターを変更できないのはなぜですか?

Related 関連記事

  1. 1

    別のライブラリからの関数の戻り値をオーバーライドします

  2. 2

    AngularJS-オーバーライドディレクティブのコンパイル関数はリンク関数を呼び出しませんか?

  3. 3

    サブクラスから親関数をオーバーライドする方法がわかりません

  4. 4

    Javascript関数をオーバーライドしますか?

  5. 5

    JQuery関数をオーバーライドします(ロギングデコレータ)

  6. 6

    関数は基本関数をオーバーライドしますか?

  7. 7

    ディレクティブでコントローラー関数をオーバーライドするのは良い考えですか?

  8. 8

    ディレクティブのリンク関数をオーバーライドします

  9. 9

    Pythonデコレータオーバーライド関数の引数

  10. 10

    トレイト関数をオーバーライドし、オーバーライドされた関数から呼び出す方法は?

  11. 11

    サブクラスが基本クラスの仮想関数をオーバーライドするかどうかをテストします

  12. 12

    noexcept(false)デストラクタは、すべての特殊メンバー関数の例外仕様をオーバーライドしますか?

  13. 13

    PouchDBコールバック関数からデータを取得しますか?

  14. 14

    JavaコードからウェブサイトのJavaScript関数を呼び出しますか?

  15. 15

    クラスメンバー関数のアドレスを取得し、ポインターから呼び出す

  16. 16

    JSONPコールバック関数からAngularコントローラーにデータを渡します

  17. 17

    トレイト内のオブジェクト内の関数をオーバーライドします

  18. 18

    JavaScript関数オブジェクトをオーバーライドしてすべての関数呼び出しをログに記録できますか?

  19. 19

    サブタイプのオーバーロードで関数を構成することは可能ですか?

  20. 20

    メンバー関数のオーバーロードのために可変個引数テンプレートクラスから型を抽出します

  21. 21

    ライブラリからの関数のオーバーロード

  22. 22

    const関数をオーバーライドしてC ++のクラス変数を変更しますか?

  23. 23

    ローカル変数angular6のサブスクライブ関数からデータを取得します

  24. 24

    javascriptのtoString関数をオーバーライドします

  25. 25

    Rの関数を使用してサーバーからデータをダウンロードするときにforループを利用しますか?

  26. 26

    配列内のオブジェクトからオーバーライド関数を呼び出すAngelscript

  27. 27

    Typescriptの親クラスのコンストラクターからサブクラスのメンバー関数をトリガーできますか?

  28. 28

    複数の関連レコードlaravelから関連レコードのセットを取得しますか?

  29. 29

    サブクラスが仮想関数をオーバーライドするのに、親クラスのデフォルト関数パラメーターを変更できないのはなぜですか?

ホットタグ

アーカイブ