2017-08-03 72 views
2

我正在寻找一种脚本执行某些函数的方法,我不知道这些函数的名称,并在另一个模块(假定由另一个用户提供)上定义,但是用我定义的模块进行了装饰。调用装饰的外部函数

例如,外部脚本是:

from MyScript import preprocess, process, postprocess 

    @preprocess(foo, bar) 
    def external_provider_random_name(): 
     return "foo" 

    @process(foobar) 
    def external_provider_random(): 
     return "bar" 

    @postprocess(foo, bar) 
    def external_provider(): 
     return "foobar" 

我会在这在我的应用程序和执行功能(我不知道他们的名字),与使用什么能力反过来又导入装饰函数返回。

我想装修的原因成为烧瓶似乎暴露出类似的行为: 用户可以通过装饰功能与[email protected](my/route)定义新的路线。这个函数然后在路由上执行一个http调用时执行,并且应用程序可以使用函数返回的任何内容(一个json)将其返回给用户。

然而,似乎行为不符合装饰者的实际定义,我看不出我是如何实现这样的。我在这里错过了什么,或者是否只有使用装饰器的解决方案?

+0

注意函数后面添加'函数=装饰(功能)'就是相当于增加了'@ decorator'前它。 –

+0

这就是我可以在函数调用中添加操作的方式。但是我仍然无法确定如何调用函数,因为我无法访问它的名字。 – AugBar

+0

你不需要一个函数的名字来调用它。你只需要对函数的引用,这正是传递给你的装饰器的东西。 – jasonharper

回答

2

您只需从包装内松开传入函数的副本即可。您可以用全局名称,listdict或您选择的其他方式存储函数引用。

这里是MyScript.py一个例子存储其函数的引用在dict

funcs = { } 

def preprocess(*args): 
    def wrapper(fn): 
     funcs['preprocess'] = fn 
     return fn 
    return wrapper 

def process(*args): 
    def wrapper(fn): 
     funcs['process'] = fn 
     return fn 
    return wrapper 

def postprocess(*args): 
    def wrapper(fn): 
     funcs['process'] = fn 
     return fn 
    return wrapper 

所有的初始化后,可以正是如此调用功能:

MyScript.funcs['preprocess']() 
+1

在这一点上,就像在'flask'中一样,使用一个类来封装状态可能是有意义的,其中装饰器可调用实际上是一个对象的方法。 –

+0

同意。我只是选择了一个全球的'dict'作为一个易于理解的例子。 –

2

好像你想要创建某种功能注册表。下面是一个简单的示例实现,它使用字典来跟踪注册的函数。

class Tracker(dict): 
    def register(self, identifier): 
     def wrapper(function): 
      self[identifier] = function 
      return function 
     return wrapper 


tracker = Tracker() 

@tracker.register('A') 
def function_A(): 
    print('Blah') 

tracker['A']() # Blah 

如果你想注册一个已定义的函数,你可以使用:

tracker.register('A')(function_A) 
+0

我非常喜欢这个想法。如果function_A的定义在脚本之外,在外部脚本之外,这将如何工作 - 我们称之为external.py? – AugBar

+0

@AugBar我不确定我是否知道你的意思,但我已经更新了答案,可能是为了解决这个问题。 –

+0

该函数的定义与跟踪器实例相同。我需要在一个单独的文件中完成这项工作。但我认为我有解决方案,就像完成烧瓶和蓝图一样! – AugBar