2011-01-19 24 views
13

オブジェクトが初期化されたクラスをXMLコードの束である で作成します。クラスは、そのXMLからさまざまなパラメータを抽出し、オブジェクト状態変数内にそれらをキャッシュする機能を持っています。これらのパラメータの潜在的な量は大きく、おそらくユーザーは大部分を必要としません。そのため、私は「怠惰な」初期化を実行することに決めました。副作用のゲッター

次のテストケースでは、このようなパラメータはtitleです。ユーザーが最初にそれにアクセスしようとすると、getter関数は、XMLを解析し、適切な状態変数を初期化し、その値を返します。

class MyClass(object):  
    def __init__(self, xml=None): 
     self.xml = xml 
     self.title = None 

    def get_title(self): 
     if self.__title is None: 
      self.__title = self.__title_from_xml() 
     return self.__title 

    def set_title(self, value): 
     self.__title = value 

    title = property(get_title, set_title, None, "Citation title") 

    def __title_from_xml(self): 
     #parse the XML and return the title 
     return title   

これは良さそうに見えますし、私のために正常に動作します。しかし、ゲッター関数は実際にはオブジェクトに非常に重大な副作用があるという意味では "セッター"であるという事実によって少し邪魔されています。これは正当な懸念ですか?もしそうなら、どのように私はそれに対処する必要がありますか?

+3

質問に対する実際の回答が何であるかにかかわらず、先頭の二重下線は使用しないでください。彼らは名前のマングリング、すなわち多くの潜在的な痛みとゼロ利得を開始します。単一の先頭のアンダースコアを使用してください。 – delnan

+1

なぜそれが問題なのかわかりません。 –

+1

マイナーリファクタリング提案:コンストラクタで 'self._title'を初期化せず、ゲッターの条件を' not hasattr(self、 "_title") 'で置き換えてください。 –

答えて

4

ゲッターは確かに副作用がありますが、これは伝統的に悪い副作用とは考えられないことです。ゲッターは常に同じ状態を返すので(状態の間に変化があっても)、ユーザーには見えない副作用はありません。これはプロパティの典型的な使用ですので、心配する必要はありません。

+0

私は同意しないことにします。この場合、XMLを解析すると例外が発生する可能性があります。また、XMLアクセス解析の例外が発生する可能性があります。私が引き継いだプロジェクトでは非常によく似たケースがありました。コードのこの部分を再インスタンス化して構文解析を行うようにしました。したがって、XMLが何らかの形で破損しても例外は起こりません。 getプロパティは例外を発生させるべきではありません。あなたは何かを上げるための単純な属性アクセスを期待していますか?計算された属性は、単純なものと同じくらい安全でなければなりません。 –

14

このデザインパターンはLazy initializationと呼ばれ、正式な使用方法があります。

+0

cf受け入れられた答えに対する私のコメント - 怠惰な初期化は問題ありませんが、それはプロパティへのアクセスが何かを起こさせるべきではありません。あなたのクラスが遅い初期化を使用している場合は、これが決して例外を意味することは決してないか、またはユーザが平凡な安全な属性アクセスを行っていると思うように誘導し、ゲッターを明示的にするその例外。 –

0

かなり遅いですが、うまくいきません:怠惰な初期化自体は問題ありませんが、誰かがオブジェクトのtitleにアクセスするまで、xml解析などを延期しません。計算された属性はプレーンな属性のように振る舞い、平文の属性アクセスはになりません。 raise(もちろん属性が存在すると仮定します)。

FWIW以前の開発者がOPの例とまったく同じ方法でプロパティを使用していたため、XMLパースエラーが最も予想外の場所で発生したため、私が引き継いだプロジェクトで非常に似たケースがありました。それはインスタンス化時に解析と検証の部分を置くことによってそれです。

そうでは、場合にのみ、としたときに最初にアクセスする決して昇給を知っ遅延初期化のプロパティを使用します。実際には、(少なくとも設定が異なる状況では)何かのためにプロパティを使用しないでください。それ以外の場合は、プロパティを使用しないで、ゲッターを明示的なメソッドにし、明示的に文書化してください。

注意:何かをキャッシュするためのプロパティを使用することはここでは問題ではありませんが、これだけで問題ありません。