2017-07-11 6 views
1

私が行っているいくつかのラボ実験の結果にはExperimentというクラスを定義しました。アイデアは一種のデータベースを作成することでした。実験を追加すると、これは終了時にデータベースに保存され、起動時に再読み込みされます(クラスレジストリに追加されます)。既に存在する場合は新しいクラスを作成するのではなく、クラスインスタンスを返す

私のクラス定義は次のとおりです。

def checkhash(hashdat): 
    for exp in cl.Experiment: 
     if exp.hashdat == hashdat: 
      return exp 
    return False 

だから、私は以前に追加した実験を追加する場合は、この:結果を含むファイルのハッシュをチェックする機能がある

class IterRegistry(type): 
    def __iter__(cls): 
     return iter(cls._registry) 


class Experiment(metaclass=IterRegistry): 
    _registry = [] 
    counter = 0 

    def __init__(self, name, pathprotocol, protocol_struct, pathresult, wallA, wallB, wallC): 
     hashdat = fn.hashfile(pathresult) 
     hashpro = fn.hashfile(pathprotocol) 
     chk = fn.checkhash(hashdat) 
     if chk: 
      raise RuntimeError("The same experiment has already been added") 
     self._registry.append(self) 
     self.name = name 
     [...] 

fn.checkhashながら上書きされません。

エラーが発生するのではなく、既存のインスタンスが既に存在する場合は、何とか元のインスタンスに戻すことはできますか?

答えて

1

あなただけではなく、中に初期化の作成をカスタマイズしたい場合は、__new__を使用することができます新しく作成されたオブジェクト:

class Experiment(metaclass=IterRegistry): 
    _registry = [] 
    counter = 0 

    def __new__(cls, name, pathprotocol, protocol_struct, pathresult, wallA, wallB, wallC): 
     hashdat = fn.hashfile(pathresult) 
     hashpro = fn.hashfile(pathprotocol) 
     chk = fn.checkhash(hashdat) 
     if chk:      # already added, just return previous instance 
      return chk 
     self = object.__new__(cls) # create a new uninitialized instance 
     self._registry.append(self) # register and initialize it 
     self.name = name 
     [...] 
     return self     # return the new registered instance 
+0

ありがとうございます。これは最善の解決策に見えますが、私は短い質問があります。私は常に '__new__ 'を上書きすることは良い方法ではないことを知っています。 "一般的には、str、int、unicode、tupleのような不変型をサブクラス化しない限り、' __new__'をオーバーライドする必要はありません。 '__new__'のすべての属性を初期化するのはいいですか? – David

+0

@ david23:新しいインスタンスを求めるときに既存のインスタンスを返すことは一般的な使用例ではなく、 '__new__'のオーバーライドのための正しいインスタンスの1つです。もう1つは不変型です。 –

1

この方法(非常に単純化した例)、それを行うようにしてください(私はそれができません__init__ブロックに知っている):

class A: 
    registry = {} 

    def __init__(self, x): 
     self.x = x 

    @classmethod 
    def create_item(cls, x): 
     try: 
      return cls.registry[x] 
     except KeyError: 
      new_item = cls(x) 
      cls.registry[x] = new_item 
      return new_item 


A.create_item(1) 
A.create_item(2) 
A.create_item(2) # doesn't add new item, but returns already existing one 
+0

ご回答ありがとうございます。これはいい練習ですか?このソリューションでは、実際には '__init__'の外にあるすべての属性を定義し、' create_item() 'メソッドを明示的に呼び出すことでオブジェクトをインスタンス化する必要があります – David

+0

答えたコードを編集しました。これで' __init__ () 'メソッドを呼び出してインスタンスを初期化します。はい、 'A()'ではなく 'A.create_item()'を呼び出す必要がありますが、IMHOは '__new __()'の "magical"オーバーライドよりも悪いです – bakatrouble

+0

'registry'を' dict'コレクションに書き直しました。そこから値を抽出するほうが効率的かもしれません。 – bakatrouble

関連する問題