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

How do I get the value of an argument passed to a decorator in Python?

根据下面的代码,我正在尝试识别发送给 class.

使用的装饰器的参数

具体来说,我正在尝试识别传递给 make_hyper 装饰器的值 100,该装饰器在 Dog class.[=19= 中使用]

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

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 和其他一些东西,并且(尽我所能)搜索 Whosebug 和整个互联网,但我找不到解决方案。

如有任何帮助,我们将不胜感激!感谢您的宝贵时间!

更新: 有人要我澄清我想做什么。抱歉没有说清楚。

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

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')

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

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

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

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)