Подтвердить что ты не робот

Применять декоратор для каждого метода в классе?

У меня есть декоратор @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()"
4b9b3361

Ответ 1

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

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)

Ответ 2

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

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

from inspect import ismethod, getmembers
for name, obj in getmembers(TestCase, ismethod):
   if name.startswith("test_"):
       setattr(TestCase, name, login_testuser(obj))

Ответ 3

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

Ответ 4

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