2011-06-20 13 views
6

私はいくつかの値を属性として保存するためのクラスのような辞書を持っています。私は最近、属性が存在しない場合、Noneを返すようなロジック(__getattr__)を追加しました。すぐに私はこのピクルスが墜落したのですが、なぜ私はいくつかの洞察を求めていました。__getattr__のデフォルト値を返そうとすると、Python pickleクラッシュが発生する

テストコード:

import cPickle 
class DictionaryLike(object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

    def __iter__(self): 
     return iter(self.__dict__) 

    def __getitem__(self, key): 
     if(self.__dict__.has_key(key)): 
      return self.__dict__[key] 
     else: 
      return None 

    ''' This is the culprit...'''  
    def __getattr__(self, key): 
     print 'Retreiving Value ' , key 
     return self.__getitem__(key) 

class SomeClass(object): 
    def __init__(self, kwargs={}): 
     self.args = DictionaryLike(**kwargs) 


someClass = SomeClass() 
content = cPickle.dumps(someClass,-1) 
print content 

結果:私は愚かな何かを

Retreiving Value __getnewargs__ 
Traceback (most recent call last): 
    File <<file>> line 29, in <module> 
    content = cPickle.dumps(someClass,-1) 
TypeError: 'NoneType' object is not callable` 

をしましたか? deepcopy()がキーが存在しない場合に例外をスローする必要があるかもしれない投稿を読んでいましたか?この場合、例外をスローせずに私が望むものを達成するための簡単な方法はありますか?

最終結果は、いくつかのコール

someClass.args.i_dont_exist 

が、私はそれがNoneを返したい場合ということです。

答えて

13

__getattr__の実装は、存在しないすべての属性に対して呼び出されるため、少しトリッキーです。あなたの場合、pickleモジュールは、__getnewargs__特殊メソッドのクラスをテストし、明らかに呼び出し可能ではないNoneを受け取ります。

あなたは魔法の名前のための基本実装を呼び出すために__getattr__を変更する場合があります

def __getattr__(self, key): 
    if key.startswith('__') and key.endswith('__'): 
     return super(DictionaryLike, self).__getattr__(key) 
    return self.__getitem__(key) 

私は内部のシンボルのために魔法を回避できるように、私は通常、アンダースコアで始まるすべての名前を通過します。

+0

これは私の場合には最適かもしれないと思う。_と\ _ \ _は決して属性名ではないからだ。 – Nix

+0

これは本当に賢いです私はそれを行うことを考えたことがない – GWW

+0

あなたはここで私をとても救ったよ – Greg

5

あなたは属性がクラスに存在しない場合AttributeErrorを調達する必要があります。

def __getattr__(self, key): 
    i = self.__getitem__(key) 
    if i == None: 
     raise AttributeError 
    return self.__getitem__(key) 

私は、この動作が必要とされていると仮定するつもりです。 getattrのpythonのドキュメントから、 "属性参照が通常の場所で属性を見つけられなかった場合(つまり、インスタンス属性でも、自己のクラスツリーでも見つからない場合)に呼び出されます。 (計算された)属性値を返すか、AttributeError例外を発生させる必要があります。 "

pickleなどに、例外を発生させない限り、探している属性が見つからないことを伝える方法がありません。たとえば、エラーメッセージpickleが__getnewargs__という特殊な呼び出し可能メソッドを探している場合、pickleは、AttributeError例外が見つからない場合に戻り値が呼び出されると予想します。

私はあなたの周りの潜在的な仕事が、多分、ピクルスがダミーメソッドとして探している特別なメソッドをすべて定義しようと思いますか?

+0

これを回避する方法はありますか(私の最後の編集を見ましたか?) – Nix

+0

@Nix:ああ、私はあなたの最後のコメントを見ませんでした – GWW

+0

私は欲しいものを得ることができないかもしれません...私はちょうどhasattr毎回チェックすることを回避したいと思った。 – Nix