12

で始まるメソッドと終わるメソッド以外の、特定のクラスのすべてのメソッドに同じデコレータを適用したいと考えています__

クラスデコレータを使用して実行できるはずです。注意すべき落とし穴はありますか?

理想的には、次のこともできるようになりたいです。

  1. 一部のメソッドでは、特別なデコレータでマークすることにより、このメカニズムを無効にします
  2. サブクラスに対してもこのメカニズムを有効にします
  3. 実行時にこのクラスに追加されるメソッドに対しても、このメカニズムを有効にします

[注: 私は Python 3.2 を使用しているので、最近追加された機能に依存していれば問題ありません。]

これが私の試みです:

_methods_to_skip = {}

def apply(decorator):
  def apply_decorator(cls):
    for method_name, method in get_all_instance_methods(cls):
      if (cls, method) in _methods_to_skip:
        continue
      if method_name[:2] == `__` and method_name[-2:] == `__`:
        continue
      cls.method_name = decorator(method)
  return apply_decorator

def dont_decorate(method):
  _methods_to_skip.add((get_class_from_method(method), method))
  return method

ここに私が問題を抱えているものがあります:

  • get_all_instance_methods関数の実装方法
  • 私のcls.method_name = decorator(method)行が正しいかどうかわからない
  • 実行時にクラスに追加されたメソッドに同じことを行う方法
  • これをサブクラスに適用する方法
  • 実装方法get_class_from_method
4

2 に答える 2

16

実行時とサブクラスのメソッド装飾の両方を処理するために、これはメタクラスで行う方がよいと思います。クラス デコレータを使用してサブクラスを自動的に処理するエレガントな方法がわかりません。

from types import FunctionType

# check if an object should be decorated
def do_decorate(attr, value):
    return ('__' not in attr and
            isinstance(value, FunctionType) and
            getattr(value, 'decorate', True))

# decorate all instance methods (unless excluded) with the same decorator
def decorate_all(decorator):
    class DecorateAll(type):
        def __new__(cls, name, bases, dct):
            for attr, value in dct.iteritems():
                if do_decorate(attr, value):
                    dct[attr] = decorator(value)
            return super(DecorateAll, cls).__new__(cls, name, bases, dct)
        def __setattr__(self, attr, value):
            if do_decorate(attr, value):
                value = decorator(value)
            super(DecorateAll, self).__setattr__(attr, value)
    return DecorateAll

# decorator to exclude methods
def dont_decorate(f):
    f.decorate = False
    return f

そして、その使用例 (Python 2 ですが、Python 3 用に簡単に変更されています):

def printer(f):
    print f
    return f

class Foo(object):
    __metaclass__ = decorate_all(printer)
    def bar(self):
        pass
    @dont_decorate
    def baz(self):
        pass
    @classmethod
    def test(self):
        pass
# prints
# <function bar at 0x04EB59B0>

class AnotherName(Foo):
    def blah(self):
        pass
# prints
# <function blah at 0x04EB5930>

Foo.qux = lambda: 1
# prints
# <function <lambda> at 0x04EB57F0>
于 2012-04-08T23:19:46.713 に答える
0

これを行うことができます(ただし、これが最もエレガントな方法かどうかはわかりません):

def get_all_instance_methods(x):
    return filter(callable, map(lambda d: getattr(x, d), dir(x)))

についてはcls.method_name、 を使用する必要がありますgetattr(cls, method_name)

于 2012-04-08T23:28:12.260 に答える