1

ファクトリ関数などに関する以前のSOの議論をたくさん読んできましたが、この特定の状況に対する最良の(pythonic)アプローチが何であるかはまだわかりません。拡張しようとしているモジュールを変更せずにソリューションを機能させたいという点で、問題にやや人為的な制約を課していることを前もって認めます。変更を加えることができますが、そのままにしておく必要があると仮定しましょう。 -この状況でのベストプラクティスを理解しようとしているからです。

私はhttp://pypi.python.org/pypi/icalendarモジュールを使用しています。このモジュールは、Icalendar 仕様 (以下、ical) からの解析とシリアル化を処理します。テキストを辞書のような「コンポーネント」オブジェクトの階層に解析します。ここで、すべての「コンポーネント」は、さまざまな有効な ical 型 (VCALENDAR、VEVENT など) を実装する単純な派生クラスのインスタンスであり、それらはすべてによって吐き出されます。共通の親クラスからの再帰ファクトリ:

class Component(...):
  @classmethod
  def from_ical(cls, ...)

独自のジェネレーター関数を含む、ical 'Calendar' クラスを拡張する 'CalendarFile' クラスを作成しました。

class CalendarFile(Calendar):
  @classmethod
  def from_file(cls, ics):

ファイル ( ) を開き、icsそれを渡します。

     instance = cls.from_ical(f.read())

他のいくつかのものを初期化および変更しinstanceてから返します。問題は、が であるにもかかわらず、 がオブジェクトではなくオブジェクトになってinstanceしまうことです。ical モジュールのファクトリ関数に入ってそこをいじる以外に、そのオブジェクトを「CalendarFile」として本質的に「再キャスト」する方法はありますか?CalendarCalendarFileclsCalendarFile

私が検討した代替案(元のモジュールを変更せずに)は次のとおりです。

  • クラスをCalendarFilehas-aCalendarクラスにします(各インスタンスはオブジェクトの独自の内部インスタンスを作成しCalendarます)が、それは整然としたものに見えます。
  • 返されたオブジェクトをいじって、必要なメソッドを提供します(カスタマイズされたオブジェクトを作成するための用語があることは知っていますが、それは私をエスケープします)。
  • 追加のメソッドを関数にして、 のインスタンスで動作させるだけですCalendar
  • または、おそらく答えは、そもそもモジュールからサブクラス化しようとするべきではなく、このタイプのコードはモジュール自体に属しているということです。

繰り返しますが、「最良の」アプローチが何であるかを理解しようとしており、代替案が欠けているかどうかも学びます。ありがとう。

4

1 に答える 1

0

通常、クラスメソッドとして定義された代替コンストラクターは、単にクラスの標準コンストラクターを呼び出し、受け取った引数を標準コンストラクターへの有効な引数に変換することを期待します。

>>> class Toy(object):
...     def __init__(self, x):
...         self.x = abs(x)
...     def __repr__(self):
...         return 'Toy({})'.format(self.x)
...     @classmethod
...     def from_string(cls, s):
...         return cls(int(s))
... 
>>> Toy.from_string('5')
Toy(5)

ほとんどの場合、このようなアプローチを強くお勧めします。これは、代替コンストラクターのゴールド スタンダードです。

しかし、これは特殊なケースです。

ソースを調べたところ、新しいクラスを追加する最善の方法は、モジュールを直接編集することだと思います。それ以外の場合は、継承を破棄し、オプション 1 (「has-a」オプション) を使用します。異なるクラスはすべて、同じコンテナー クラスのわずかに異なるバージョンです。これらは、実際には別個のクラスであってはなりません。しかし、書かれているコードのイディオムに新しいクラスを追加したい場合は、モジュール自体に新しいクラスを追加する必要があります。さらに、from_iter欺瞞的な名前が付けられています。それは実際にはコンストラクターではありません。スタンドアロン機能であるべきだと思います。一緒にリンクされたコンポーネントのツリー全体を構築し、個々のコンポーネントを構築するコードは、スタンドアロン関数である必要があるがそうではないさまざまなファクトリ関数への呼び出しのチェーンに埋もれています。IMOそのコードの多くは、サブクラス化に__init__役立つ場所に配置する必要がありますが、そうではありません。

Component実際、メソッドを追加するサブクラスはありません。のサブクラスにメソッドを追加することCalendarで、コードの実際のイディオムを完全に無視しています。私はそのイディオムがあまり好きではありませんが、そのイディオムを無視することで、あなたはそれをさらに悪化させています. 元のモジュールを変更したくない場合は、ここで継承を忘れて、オブジェクトに has-a 関係を与えてくださいCalendar。変更しないでください__class__。標準の OO プラクティスに従う独自のOO 構造を確立します。

于 2013-09-19T16:18:20.143 に答える