自动发现python装饰器

时间:2018-11-22 20:38:11

标签: python decorator faust

我想知道是否有标准化的方法或最佳实践来扫描/自动发现装饰器,就像here一样,但是在其他几个库中(例如Django,Flask)也是如此。通常,装饰器会在当时恰好提供内部功能的时候提供额外的/包装功能。

在下面的示例中,在Flask / Django(路由装饰器)中也使用了装饰器来添加总体功能,例如首先在装饰器逻辑中生成tcp客户端,然后在收到处理该消息的消息时调用内部func。

Flask / Django注册一个URL路由,其中​​仅在以后请求URL时才调用内部函数。所有示例都需要对装饰器逻辑进行初始注册(扫描/发现),才能首先启动总体功能。在我看来,这似乎是装饰器的另一种用法,我想了解最佳实践方法(如果有)。

请参见下面的Faust示例,其中装饰器app.agent()在asyncio事件循环内自动触发侦听(kafka流)客户端,然后内部函数hello()处理传入的消息稍后,仅当收到消息时,需要在脚本开始时首先进行相关装饰器逻辑的初始检查/扫描/发现。

import faust

class Greeting(faust.Record):
    from_name: str
    to_name: str

app = faust.App('hello-app', broker='kafka://localhost')
topic = app.topic('hello-topic', value_type=Greeting)

@app.agent(topic)
async def hello(greetings):
    async for greeting in greetings:
        print(f'Hello from {greeting.from_name} to {greeting.to_name}')

@app.timer(interval=1.0)
async def example_sender(app):
    await hello.send(
        value=Greeting(from_name='Faust', to_name='you'),
    )

if __name__ == '__main__':
    app.main()

1 个答案:

答案 0 :(得分:2)

什么都没有“发现”。当您import包中的模块时,将执行所有该代码。这就是为什么我们有if __name__ == '__main__'来停止在导入时执行某些代码的原因。当您运行代码时,装饰器将被“发现”。

我认为Flask blueprint是一个很好的例子。 Here可以看到导入模块时它如何注册url端点。它所做的就是将其追加到列表中:

    def route(self, rule, **options):
        """Like :meth:`Flask.route` but for a blueprint.  The endpoint for the
        :func:`url_for` function is prefixed with the name of the blueprint.
        """
        def decorator(f):
            endpoint = options.pop("endpoint", f.__name__)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

代码运行,装饰器被评估,他们只需要保留一些内部所有装饰函数的列表。它们存储在Blueprint对象中。