zoukankan      html  css  js  c++  java
  • 学习Python动态扩展包stevedore

    1.stevedore作用

    Python导入动态代码很容易,例如通过在运行时导入扩展插件来扩展你的应用。许多应用通过__import__或importlib实现了这个功能。stevedore的功能就是管理扩展的,但是它的实现方式是借助steuptools的entry points(我的上一篇有讲entry points功能)。

    2.创建一个插件

    这里以一个格式转换的例子来学习:

    # stevedore/example/base.py
    import abc
    class FormatterBase(object):
        __metaclass__ = abc.ABCMeta
    
        def __init__(self, max_width=60):
            self.max_width = max_width
    
        @abc.abstractmethod
        def format(self, data):
            pass
    

    首先创建一个基类,来作为虚拟基础类,供插件们继承并实现其中方法。这个例子中的关键函数为format,其子类都需要实现这个函数。

    有关虚拟基础类的内容在我之前的一篇博客中也说到。

    接下来是实现功能的两个插件类:

    # stevedore/example/simple.py
    from stevedore.example import base
    class Simple(base.FormatterBase):
        def format(self, data):
            for name, value in sorted(data.items()):
                line = '{name} = {value}n'.format(
                    name=name,
                    value=value,
                )
                yield line
    

    另一个:

    # stevedore/example/fields.py
    import textwrap
    from stevedore.example import base
    class FieldList(base.FormatterBase):
        def format(self, data):
            for name, value in sorted(data.items()):
                full_text = ': {name} : {value}'.format(
                    name=name,
                    value=value,
                )
                wrapped_text = textwrap.fill(
                    full_text,
                    initial_indent='',
                    subsequent_indent='    ',
                    width=self.max_width,
                )
                yield wrapped_text + 'n'
    

    这两个插件以不同的方式对传入的数据进行格式化,并且都实现了format方法,接下来是在setup.py中注册插件:

    # stevedore/example/setup.py
    from setuptools import setup, find_packages
    setup(
        ...
        entry_points={
            'stevedore.example.formatter': [
                'simple = stevedore.example.simple:Simple',
                'field = stevedore.example.fields:FieldList',
                'plain = stevedore.example.simple:Simple',
            ],
        },
    )
    

    这个例子可以看到,我们设定了三个接口,simple/field/plain,其他应用或者自身都可以对它们进行调用。如果不用stevedore的话,直接使用pkg_resources.require()调用他们,但是stevedore有了一个更好的机制来管理和使用他们

    3.导入插件

    stevedore定义了一系列类来帮助更好的调用上 大专栏  学习Python动态扩展包stevedore面生成的插件

    以Driver方式调用

    这种方式经常被使用,即我们有多个方法可以做成一件事,但是我们只用其中一种就够了,通过stevedore的DriverManager可以做到,如下:

    # stevedore/example/load_as_driver.py
    from __future__ import print_function
    import argparse
    from stevedore import driver
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument(
            'format',
            nargs='?',
            default='simple',
            help='the output format',
        )
        parser.add_argument(
            '--width',
            default=60,
            type=int,
            help='maximum output width for text',
        )
        parsed_args = parser.parse_args()
        data = {
            'a': 'A',
            'b': 'B',
            'long': 'word ' * 80,
        }
        mgr = driver.DriverManager(
            namespace='stevedore.example.formatter',
            name=parsed_args.format,
            invoke_on_load=True,
            invoke_args=(parsed_args.width,),
        )
        for chunk in mgr.driver.format(data):
            print(chunk, end='')
    

    这里关键的位置在mgr生成部分,首先根据namespace获得相应entry point组,然后根据name调用响应的plugin

    例如python -m stevedore.example.load_as_driver a = A即以默认的name调用plugin,默认的format为simple。python -m stevedore.example.load_as_driver field为调用field的plugin

    以Extensions方式调用

    另外一种常见的方式是调用多个plugin共同处理一件事情,这可以利用ExtensionManagerNamedExtensionManagerEnabledExtensionManger来实现

    # stevedore/example/load_as_extension.py
    from __future__ import print_function
    
    import argparse
    
    from stevedore import extension
    
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument(
            '--width',
            default=60,
            type=int,
            help='maximum output width for text',
        )
        parsed_args = parser.parse_args()
    
        data = {
            'a': 'A',
            'b': 'B',
            'long': 'word ' * 80,
        }
    
        mgr = extension.ExtensionManager(
            namespace='stevedore.example.formatter',
            invoke_on_load=True,
            invoke_args=(parsed_args.width,),
        )
    
        def format_data(ext, data):
            return (ext.name, ext.obj.format(data))
    
        results = mgr.map(format_data, data)
    
        for name, result in results:
            print('Formatter: {0}'.format(name))
            for chunk in result:
                print(chunk, end='')
            print('')
    

    这里ExtensionManger的参数只需要namespace,因为它将使用这个entry point组中的所有插件,并且通过mgr.map()来为每一个plugin传递参数

    其他

    除了上面提到的几种方式外,还有其他几种可以使用,具体可以自己研究了~

  • 相关阅读:
    2. Add Two Numbers
    1. Two Sum
    22. Generate Parentheses (backTracking)
    21. Merge Two Sorted Lists
    20. Valid Parentheses (Stack)
    19. Remove Nth Node From End of List
    18. 4Sum (通用算法 nSum)
    17. Letter Combinations of a Phone Number (backtracking)
    LeetCode SQL: Combine Two Tables
    LeetCode SQL:Employees Earning More Than Their Managers
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12432918.html
Copyright © 2011-2022 走看看