【问题标题】:Applying a decorator to every method in a class?将装饰器应用于类中的每个方法?
【发布时间】:2010-02-10 14:51:10
【问题描述】:

我已将装饰器@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()"

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    在 Python 2.6 中,class decorator 绝对是要走的路。例如,对于这些类型的任务,这是一个非常通用的任务:

    import inspect
    
    def decallmethods(decorator, prefix='test_'):
        def dectheclass(cls):
            for name, m in inspect.getmembers(cls, inspect.isfunction):
                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 的用途:它在每个测试方法之前运行。

      【讨论】:

      • 感谢您的建议,但我希望仅将装饰器应用于具有特定前缀的方法,而 setUp 将应用于所有方法。
      • 也许将这些方法分离到它们自己的类中呢?神奇的检查和方法的增强听起来像是一个神秘的维护头痛。
      【解决方案4】:

      是的,您可以循环遍历类的 dir/__dict__ 或拥有一个这样做的元类,识别属性是否以“test”开头。但是,与显式编写装饰器相比,这将创建不那么直接、显式的代码。

      【讨论】:

        猜你喜欢
        • 2016-07-24
        • 2021-04-20
        • 2011-10-05
        • 2020-11-30
        • 2012-08-07
        • 2014-03-20
        • 2016-12-31
        • 1970-01-01
        • 2016-03-17
        相关资源
        最近更新 更多