用装饰器函数填充字典

时间:2018-02-28 00:31:16

标签: python python-3.x

我正在创建一个基本上运行一堆测试的应用程序,每个测试都是一个单独的函数。我有一个测试/函数列表就像这样的字典。

test = {
    "test 1": f1,
    "test 2": f2,
    "test 3": f3
}

我可以执行这样的功能:

for testn, _ in test.items():
    test[testn]()

但我想做这样的事情:

tests = {}

@task("test 1")
def f1():
   ...

@task("test 2")
def f1():
   ...

def run():
    for testn, _ in tests:
        tests[test]()

我想知道这怎么可能。任何帮助,将不胜感激。

1 个答案:

答案 0 :(得分:4)

您可以创建一个简单的装饰器来填充您的函数注册表tests

tests = {}
def task(name):
   def wrapper(funct):
      tests[name] = funct
      return funct
   return wrapper

@task("test 1")
def f1():
  ...

@task("test 2")
def f2():
  ...

def run():
  for testn, _ in tests.items():
    tests[test]()

现在,在调用run之前,当迭代字典时,可以观察到结构是正确的:

print({a:b.__name__ for a, b in tests.items()})

输出:

{'test 2': 'f2', 'test 1': 'f1'}

但请注意,tests确实包含所有函数实例:

{'test 2': <function f2 at 0x10de0e5f0>, 'test 1': <function f1 at 0x10de0e578>}

这个装饰器略微偏离接收包装函数的正常装饰器模式,拦截参数,并通过仅返回传递给它的原始函数对象来调用包装函数。这节省了空间,不必实现另一个包装器来拦截参数,并允许在函数绑定到其对象时立即添加注册表。

另请注意,tests是一个字典,因此尝试通过解包来迭代它而不先调用dict.items()并引发ValueError: too many values to unpack错误。

编辑:如果函数成为方法,那么解决方案将是:

class Tests:
    def __init__(self):
       self.tests = {}
    def task(self, name):
       def wrapper(f):
          self.tests[name] = f
       return wrapper

test = Tests()
@test.task('test 1')
def f1():
   pass

@test.task('test 2')
def f2():
   pass

for a, b in test.tests.items():
   pass

print({a:b.__name__ for a, b in test.tests.items()})

输出:

{'test 2': 'f2', 'test 1': 'f1'}