最も重要な部分、つまりデータの形状について話すことを怠っています。ここが本当に一番重要です。「デザイン パターン」は気を散らすものです。これらのパターンの多くは、Python にはない言語の制限のために存在し、不必要な厳格さをもたらします。
- まず、データの形状を見てください。例えば:
- 最初に XML を用意します
- 次に、XML から抽出されたデータのコレクションを取得します (単純な dict? ネストされた dict? 必要なデータは? 同種か異種か? これは最も重要なことですが、あなたはそれについて話しません!)
- 次に、このデータを SQL バックエンドでシリアル化/永続化します。
- 次に、そのデータの操作を容易にするために、メソッド、プロパティ、または dict または tuple 内のアイテムの "インターフェイス" (口頭での説明) を設計します。シンプルに保ち、ネイティブの Python 型に固執する場合は、関数と dict/tuple だけで、クラスさえ必要ない場合があります。
- アプリケーションに必要なレベルの抽象化が得られるまで繰り返します。
たとえば、「extractor」のインターフェースは「xml 文字列を生成する iterable」である可能性があります。これは、ジェネレーターまたは__iter__
andnext()
メソッドを持つクラスのいずれかであることに注意してください。抽象クラスを定義してサブクラス化する必要はありません!
データに追加する構成可能なポリモーフィズムの種類は、データの正確な形状によって異なります。たとえば、規則を使用できます。
# persisters.py
def persist_foo(data):
pass
# main.py
import persisters
data = {'type':'foo', 'values':{'field1':'a','field2':[1,2]}}
try:
foo_persister = getitem(persisters, 'persist_'+data['type'])
except AttributeError:
# no 'foo' persister is available!
または、さらに抽象化が必要な場合 (おそらく、制御できない新しいモジュールを追加する必要がある場合)、レジストリ (単なる辞書) とモジュール規則を使用できます。
# registry.py
def register(registry, method, type_):
"""Returns a decorator that registers a callable in a registry for the method and type"""
def register_decorator(callable_):
registry.setdefault(method, {})[type_] = callable_
return callable_
return register_decorator
def merge_registries(r1, r2):
for method, type_ in r2.iteritems():
r1.setdefault(method, {}).update(r2[method])
def get_callable(registry, method, type_):
try:
callable_ = registry[method][type]
except KeyError, e:
e.message = 'No {} method for type {} in registry'.format(method, type)
raise e
return callable_
def retrieve_registry(module):
try:
return module.get_registry()
except AttributeError:
return {}
def add_module_registry(yourregistry, *modules)
for module in modules:
merge_registries(yourregistry, module)
# extractors.py
from registry import register
_REGISTRY = {}
def get_registry():
return _REGISTRY
@register(_REGISTRY, 'extract', 'foo')
def foo_extractor(abc):
print 'extracting_foo'
# main.py
import extractors, registry
my_registry = {}
registry.add_module_registry(my_registry, extractors)
foo_extracter = registry.get_callable(my_registry, 'extract', 'foo')
必要に応じて、この構造の上にグローバル レジストリを簡単に構築できます (ただし、グローバル状態は多少不便であっても避ける必要があります)。
公開フレームワークを構築していて、最大限の拡張性と形式主義が必要であり、複雑さを支払う意思がある場合は、次のようなものを見ることができますzope.interface
。(これは Pyramid によって使用されます。)
独自の抽出変換ロード アプリを作成するのではなく、スクレイピーを検討しましたか? スクレイピーを使用すると、文字列が与えられ、一連のアイテム (データ) またはリクエスト (取得する URL など、より多くの文字列のリクエスト) を返す「Spider」を記述できます。アイテムは構成可能なアイテム パイプラインに送られ、アイテムを渡す前に、受け取ったアイテムを必要に応じて処理します (DB に永続化するなど)。
Scrapy を使用しない場合でも、データ中心のパイプラインのような設計を採用し、具体的な「クラス」と「パターン」ではなく、抽象的な「呼び出し可能」および「反復可能」インターフェースの観点から考える必要があります。