如何在Python中获取传递给装饰器的参数的值?

时间:2018-02-22 01:00:37

标签: python decorator inspect

鉴于下面的代码,我试图找出发送给类使用的装饰器的参数。

具体来说,我正在尝试确定传递到100类中使用的make_hyper装饰器的值Dog

最理想的是,我需要能够在不直接运行方法的情况下获取此值,因为我正在使用的实际方法代码需要很长时间才能运行。

import inspect

def make_hyper(new_volume):
    def decorator(decorated_method):
        def wrapped_method(self, *args, **kwargs):
            self.volume = new_volume
            return decorated_method(self, *args, **kwargs)
        return wrapped_method
    return decorator


class Dog(object):
    def __init__(self, name):
        self.name = name
        self.volume = 1

    @make_hyper(new_volume=100)
    def bark(self):
        if self.volume >= 10:
            print('[{}]: BARK!!'.format(self.name))
        elif self.volume >= 5:
            print('[{}]: Bark!'.format(self.name))
        else:
            print('[{}]: Bark'.format(self.name))

我曾尝试使用inspect.getargspec和其他一些东西,并且(尽我所能)搜索Stackoverflow和Internet,但我找不到解决方案。

任何帮助将不胜感激!谢谢你的时间!

更新 有人让我澄清我想要做的事情。抱歉不太清楚。

上述玩具所代表的实际代码是一个测试自动化框架,其中包含指定测试标签的装饰器:

class TestTags(object):
  WIFI = 'wifi'
  BLE = 'ble'
  NIGHTLY = 'nightly'
  REGRESSION = 'regression'

class TestBase(unittest.TestCase):
  <define common test stuff and test decorators>

class ThingTester(TestBase):
  @TestBase.tags(TestTags.WIFI, TestTags.BLE, TestTags.REGRESSION)
  def test_all_the_things(self):
    <test all the things>

# what I'm trying to get
test_tags = ???
print(test_tags)  # prints out ('wifi', 'ble', 'regression')

我编写了一个实用程序,它遍历所有测试模块,类和单个测试,并创建一个定义测试计划的HTML + JavaScript页面。我想要添加到页面的一个数据是与每个测试相关联的标记。

我发现我可以让tags装饰器将属性保存到类中(即self.tags = tags),但这需要在将值保存到TestBase之前运行测试对象和我需要能够独立于运行测试而生成测试计划。

1 个答案:

答案 0 :(得分:2)

我不确定我是否完全理解您的需求,但如果您打算检查现有测试以创建计划或报告,那么您可能希望将装饰器参数存储在测试函数,而不是类实例,对吧?例如:

def TestTags(*tags):
    def decorator(f):
        def wrapper(*args, **kwargs):
            # ...
            return f(*args, **kwargs)
        wrapper.tags = tags
        return wrapper
    return decorator

@TestTags(TAG1, TAG2)
def myTest(...):
    ...

print(myTest.tags)
>>> (TAG1, TAG2)

编辑:刚刚意识到,开箱即用的方法并不开箱即用。你仍然可以像这样使用它:

def TestTags(*tags):
    def decorator(f):
        def wrapper(*args, **kwargs):
            # ...
            return f(*args, **kwargs)
        wrapper.tags = tags
        return wrapper
    return decorator

class TestSuite(...):
    @TestTags(TAG1, TAG2)
    def myTest(...):
        ...

print(TestSuite.myTest.tags)  # From class function
>>> (TAG1, TAG2)
myTestSuite = TestSuite()
print(myTestSuite.myTest.__func__.tags)  # From instance method
>>> (TAG1, TAG2)