程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Python >> 學習Python動態擴展包stevedore

學習Python動態擴展包stevedore

編輯:Python

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定義了一系列類來幫助更好的調用上面生成的插件

以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傳遞參數

其他

除了上面提到的幾種方式外,還有其他幾種可以使用,具體可以自己研究了~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved