3

単純な例外ログ デコレータがあります。これは、スクリプトが例外をスローしたときに自分自身に電子メールを送信するのに便利です。

def logExceptions(func):
   def wrapper():
      try:
         func()
      except Exception, e:
         logger.exception(e)

   return wrapper

ただし、クラス メソッドをデコレートしたい場合は、wrapper() を変更して「self」を取る必要があります。そうしないと、次のエラーが発生します。

TypeError: wrapper() takes no arguments (1 given)

もちろん、その時点で、クラス以外のメソッドを装飾するために使用することはできません。これは、次のエラーが発生するためです。

TypeError: wrapper() takes exactly 1 argument (0 given)

この問題に取り組むためのきれいな方法はありますか? ありがとうございます=)

4

3 に答える 3

7

通常は、ラッパーを定義して、ラップする関数にそれらを受け入れ*args**kwargs渡すようにします。このようにして、任意の関数をラップできます。

また、「クラスメソッド」と呼んでいるものはPythonが「インスタンスメソッド」と呼んでいるもので、「非クラスメソッド」と呼んでいるものはPythonが「関数」と呼んでいるものという印象を受けます。Python の「非クラス メソッド」(インスタンス メソッドなど) はself引数を取ります。

于 2012-09-11T03:01:35.243 に答える
5

classmethodインスタンスメソッドとの違いstaticmethod

最初の注意: 静的メソッドとクラス メソッドはどちらも関数であるため、標準の関数規則がほとんど適用されます。あなたの質問は、静的メソッド(追加の引数が渡されていない)とクラスメソッド(最初の引数でクラスを受け取る)の違いに関するものだと理解しています。

class Test(object):
    def standard_method(*args, **kwargs):
        # it is instance method (first argument will be instance)
        return args, kwargs

    @classmethod
    def class_method(*args, **kwargs):
        # it is class method (first argument will be class)
        return args, kwargs

    @staticmethod
    def static_method(*args, **kwargs):
        # it is static method (receives only arguments passed explicitly)
        return args, kwargs

証明(または自明の例)は次のとおりです。

>>> t = Test()
>>> t.standard_method()
((<__main__.Test object at 0x0000000002B47CC0>,), {})
>>> t.class_method()
((<class '__main__.Test'>,), {})
>>> t.static_method()
((), {})

ご覧のとおり、渡される引数のリストは、選択したメソッドのタイプによって異なります。あなたが直面している問題は、可変数の引数です。

解決

そのための解決策があります-引数のアンパックを使用します:

def some_decorator(func):
    def wrapper(*args, **kwargs):
        # do something here
        # args is a tuple with positional args, kwargs is dict with keyword args
        return func(*args, **kwargs)
    return wrapper

その後、によって返される関数は、some_decorator装飾された関数と同じ量の引数を受け入れます。

したがって、これらの例は両方とも機能します。

@some_decorator
def say_hello():
    print 'hello'

@some_decorator
def say_something(something):
    print something

付録

完全な例を示すために、そのような構造を使用するとよいでしょう ( の使用法に注意してくださいfunctools.wraps)。

from functools import wraps
def some_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # do something here
        # args is a tuple with positional args, kwargs is dict with keyword args
        return func(*args, **kwargs)
    return wrapper

その理由は のドキュメントにfunctools.wraps()記載されています: 関数名と docstring を保持するため、実質的にラップされた関数のように見えるラッパーになります (これは便利な場合もあります)。

于 2012-09-11T03:08:22.273 に答える
2

デコレートの代わりにsys.excepthook、キャッチされていないすべての例外に対して動作するコールバックを使用して、カスタム ロギング関数を割り当てることができます。利点は、例外をログに記録することに関心のあるすべての関数を切断する(さらに重要なことに、追跡する) 必要がないことです。

于 2012-09-11T03:08:10.127 に答える