Применение Python-декораторов к методам в классе - PullRequest
14 голосов
/ 10 февраля 2010

У меня есть декоратор @login_testuser, примененный против метода test_1 :

class TestCase(object):
    @login_testuser
    def test_1(self):
        print "test_1()"

Можно ли применить @login_testuser к каждому методу класса с префиксом "test_"?

Другими словами, декоратор будет применяться к test_1 , test_2 методам ниже, но не к setUp .

class TestCase(object):
    def setUp(self):
        pass

    def test_1(self):
        print "test_1()"

    def test_2(self):
        print "test_2()"

Ответы [ 4 ]

20 голосов
/ 10 февраля 2010

В Python 2.6 декоратор класса определенно подходит. Например, вот довольно общий пример для таких задач:

import inspect

def decallmethods(decorator, prefix='test_'):
  def dectheclass(cls):
    for name, m in inspect.getmembers(cls, inspect.ismethod):
      if name.startswith(prefix):
        setattr(cls, name, decorator(m))
    return cls
  return dectheclass

а сейчас просто

@decallmethods(login_testuser)
class TestCase(object):
    def setUp(self):
        pass

    def test_1(self):
        print "test_1()"

    def test_2(self):
        print "test_2()"

даст вам то, что вы хотите. В Python 2.5 или хуже, синтаксис @decallmethods не работает для оформления класса, но в противном случае с точно таким же кодом вы можете заменить его следующим оператором справа после конца оператора class TestCase :

TestCase = decallmethods(login_testuser)(TestCase)
3 голосов
/ 10 февраля 2010

Вы уверены, что вам не будет лучше, если вместо этого поместить код login_testuser в setUp? Вот для чего нужен setUp: он запускается перед каждым методом тестирования.

3 голосов
/ 10 февраля 2010

Конечно. Переберите все атрибуты класса. Проверьте каждый на предмет того, что он метод, и если имя начинается с «test_». Затем замените его на функцию, возвращаемую вашим декоратором

Что-то вроде:

from inspect import ismethod, getmembers
for name, obj in getmembers(TestCase, ismethod):
   if name.startswith("test_"):
       setattr(TestCase, name, login_testuser(obj))
0 голосов
/ 10 февраля 2010

Да, вы можете перебрать класс dir / __dict__ или иметь метакласс, который делает это, определяя, начинаются ли атрибуты с «test». Однако это создаст менее простой, явный код, чем явная запись декоратора.

...