Вопрос по python – Автоматически украшать каждый метод экземпляра в классе

10

Я хочу применить один и тот же декоратор к каждому методу в данном классе, кроме тех, которые начинаются и заканчиваются на__.

Мне кажется, это должно быть выполнимо, используя декоратор класса. Есть ли подводные камни, о которых следует знать?

В идеале я также хотел бы иметь возможность:

disable this mechanism for some methods by marking them with a special decorator enable this mechanism for subclasses as well enable this mechanism even for methods that are added to this class in runtime

[Примечание: я использую Python 3.2, поэтому я в порядке, если это зависит от недавно добавленных функций.]

Вот моя попытка:

<code>_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
</code>

Вот вещи, с которыми у меня проблемы:

how to implement get_all_instance_methods function not sure if my cls.method_name = decorator(method) line is correct how to do the same to any methods added to a class in runtime how to apply this to subclasses how to implement get_class_from_method
Ах, прости, прости. Полностью согласен с вашим downvote тогда. Надеюсь, обновленный вопрос в порядке. max
@anonymous downvoter: пожалуйста, будьте вежливы и прокомментируйте, что вам не нравится при понижении голосов. Является ли мой вопрос настолько плохим, что я даже не заслуживаю объяснения того, что с ним не так? max
@ Lattyware Спасибо за указание на это; Я обновил вопрос, чтобы показать, в чем моя проблема. max
Похоже, у вас есть четкое представление о том, как это сделать, вы просите людей реализовать это для вас? Если нет, то почему бы не опубликовать это после попытки, если у вас есть реальная проблема? Gareth Latty
Ненавижу это говорить, но отрицательный голос был от меня, и я изложил свои причины. Теперь вы уже дали свою реализацию, и вопрос более конкретный, я его сниму. Gareth Latty

Ваш Ответ

2   ответа
14

что это лучше сделать с метаклассом, чтобы обрабатывать как методы выполнения, так и методы подкласса. Я не вижу элегантного способа автоматически обрабатывать подклассы с помощью декоратора классов.

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>
Error: User Rate Limit Exceeded__metaclass__Error: User Rate Limit Exceededclass Foo(object, metaclass=decorate_all(printer))Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded__getattr__Error: User Rate Limit Exceeded
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).

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы