2011-11-08 6 views
1

自分自身を怠惰な変数クラスにして、別のクラスで使っています。どうやってレイジー変数クラスの属性にアクセスできますか?私は運が無ければ__getattr__を試しました。ここでは例を示します。遅延クラスの属性にアクセスするにはどうしたらいいですか?

class lazyobject(object): 
    def __init__(self,varname,something='This is the something I want to access'): 
     self.varname = varname 
     self.something = something 

    def __get__(self, obj, type=None): 
     if obj.__dict__.has_key(self.varname): 
      print "Already computed %s" % self.varname 
      return obj.__dict__[self.varname] 
     else: 
      print "computing %s" % self.varname 
      obj.__dict__[self.varname] = "something else" 
      return obj.__dict__[self.varname] 

class lazyobject2(lazyobject): 
    def __getattr__(self): 
     return self.something 

class dummy(object): 
    def __init__(self): 
     setattr(self.__class__, 'lazy', lazyobject('lazy')) 

class dummy2(object): 
    def __init__(self): 
     setattr(self.__class__, 'lazy', lazyobject2('lazy')) 

d1 = dummy() 
d2 = dummy2() 

try: 
    print "d1.lazy.something - no getattr: ",d1.lazy.something 
except: 
    print "d2.lazy is already computed - can't get its .something because it's now a string!" 
print "d1.lazy - no getattr: ",d1.lazy 

try: 
    print "d2.lazy.something - has getattr: ",d2.lazy.something 
except: 
    print "d2.lazy is already computed - can't get its .something because it's now a string!" 
print "d2.lazy - no getattr: ",d2.lazy 

この版画:

d1.lazy.something - no getattr: computing lazy 
d2.lazy is already computed - can't get its .something because it's now a string! 
d1.lazy - no getattr: something else 
d2.lazy.something - has getattr: computing lazy 
d2.lazy is already computed - can't get its .something because it's now a string! 
d2.lazy - no getattr: something else 

私はそれを印刷したいもの:

d1.lazy.something - no getattr: This is the something I want to access 
computing lazy 
d1.lazy - no getattr: something else 

上記の例は不自然ですが、私は全体のポイントを取得します願っています。私の疑問をフレーズするもう一つの方法は、クラス属性にアクセスするときに__get__メソッドをバイパスするにはどうすればいいですか?

答えて

4

迂回する方法__get__クラス属性にアクセスするときは、ドット付きアクセスではなくクラス辞書を使用して検索します。

これは、関数オブジェクトを使用して簡単に説明できます。例:あなたが欠落していた情報の

>>> class A(object): 
     def f(self): 
      pass 

>>> A.f       # dotted access calls f.__get__ 
<unbound method A.f> 
>>> vars(A)['f']    # dict access bypasses f.__get__ 
<function f at 0x101723500> 

>>> a = A() 
>>> a.f       # dotted access calls f.__get__ 
<bound method A.f of <__main__.A object at 0x10171e810>> 
>>> vars(a.__class__)['f']  # dict access bypasses f.__get__ 
<function f at 0x101723500> 

他の作品には属性が見つからない場合にのみ実行されます__getattr____get__ランを継承していることです。このロジックは、__getattribute__によって制御され、オブジェクトから継承されています。したがって、__get__をバイパスする場合は、サブクラスに新しい__get__を書き込むか、サブクラスに__getattribute__を定義してルックアップロジックを変更する必要があります。

__getattr__を置き換える、lazyobject2クラスを修正するには:要約すると

class lazyobject2(lazyobject): 

    def __getattribute__(self, key): 
     # bypass __get__ 
     return object.__getattribute__(self, '__dict__')[key] 

、この問題を解決するために使用される知識の重要な部分は、以下のとおりです。

  • object.__getattribute__ルックアップロジックを制御します。
  • まず、現在のクラスで定義されているか継承されているかにかかわらず、__get__を探します。
  • 何も見つからない場合は、object.__getattr__を呼び出します。
  • 上記の3つの手順は、ドット区切りの検索でのみ発生します。
  • これらの手順は、__dict__またはvars()経由で直接アクセスすることでバイパスできます。記述子ロジックの

詳細はthis writeupまたはthis presentationで見つけることができます。

関連する問題