如何使python装饰器像标签一样工作以进行函数调用"通过标签"

时间:2017-01-24 17:25:33

标签: python decorator python-decorators

我是一个蟒蛇初学者,并且了解装饰器的基本概念。之前我曾经使用过Python-Behave,框架允许你插入一个装饰器,它的功能就像一个标签。我试图在我目前正在构建的框架中复制它。

CLI中的自定义arg

parser = argparse.ArgumentParser()
parser.add_argument('--type', help='foo help')
args = parser.parse_args() #args.type would receive the value

CLI

python run.py --type=A

功能

   @typeA
   def foo_func():
      print "type A ran"

   @typeB
   def bar_func():
      print "type B ran"

预期输出

"type A ran"

2 个答案:

答案 0 :(得分:1)

使用装饰器在字典中存储对函数的引用。使用用户输入从字典中检索函数。之后再打电话。

REGISTER = {}

def register(name):
    def wrapper(f):
        print f, 'registered'
        REGISTER[name] = f
        return f
    return wrapper

@register('A')
def foo():
    print 'foo called'

@register('B')
def bar():
    print 'bar called'

name = 'A'  # or args.type
func_to_call = REGISTER[name]
func_to_call()  # actual call is done here

答案 1 :(得分:1)

将装饰器包装成类样式装饰器,以避免挂起变量并使用memoized工厂函数来创建标签。

import functools

class TagDecorator(object):

    def __init__(self, tagName):
        self.functions = []
        self.tagName = tagName

    def __str__(self):
        return "<TagDecorator {tagName}>".format(tagName=self.tagName)

    def __call__(self, f):
        self.functions.append(f)
        return f

    def invoke(self, *args, **kwargs):
        return [f(*args, **kwargs) for f in self.functions]


@functools.lru_cache(maxsize=None)  # memoization
def get_func_tag(tagName):
    return TagDecorator(tagName)

现在我们创建标签:

tagA = get_func_tag("A")
tagB = get_func_tag("B")

@tagA
def funcA_1(*args, **kwargs):
    print("A", args, kwargs)

# another way
@get_func_tag("A")
def funcA_2(*args, **kwargs):
    print("A too", args, kwargs)

@tagB
def funcB_1():
    print("B")

@tagB
def funcB_2():
    print("B too")

# invoke all functions registered with tagA : passing arguments
tagA.invoke("hello", who="dolly")

# invoke all functions registered with tagA, another way.
get_func_tag("A").invoke()

# actually get_func_tag always returns the same instance
# for a given tagName, thanks to lru_cache
assert get_func_tag("A") == tagA

# Of course tagB can be invoked
tagB.invoke()
get_func_tag("B").invoke()

# but passing it args would be an error.
tagB.invoke("B")  # TypeError: funcB_1() takes 0 positional arguments but 1 was given

必须注意标记的功能&#39;参数。如果对于同一个标签,您注册了不同的签名,则在调用它们时肯定会遇到问题。您可以使用inspect.signature功能处理此问题。但真正的签名匹配有点棘手。