2009-12-27 40 views
1

下一個是我的代碼:爲什麼getattr()不能像我認爲的那樣工作?我認爲此代碼應打印「SSS」

class foo: 
    def __init__(self): 
     self.a = "a" 
    def __getattr__(self,x,defalut): 
     if x in self: 
      return x 
     else:return defalut 

a=foo() 
print getattr(a,'b','sss') 

我知道__getattr__必須是2的說法,但我想獲得一個默認屬性,如果屬性是不存在。

我怎樣才能得到它,謝謝


,我發現如果定義__setattr__,我的下一個代碼也不能運行

class foo: 
    def __init__(self): 
     self.a={} 
    def __setattr__(self,name,value): 
      self.a[name]=value 

a=foo()#error ,why 

喜亞歷克斯, 我改變了你的例子:

class foo(object): 
    def __init__(self): 
     self.a = {'a': 'boh'} 
    def __getattr__(self, x): 
     if x in self.a: 
      return self.a[x] 
     raise AttributeError 

a=foo() 
print getattr(a,'a','sss') 

它打印{「一」:「噓」},而不是「噓」 我認爲這將打印self.a不self.a [「一」],這顯然不希望看到

爲什麼,有什麼辦法來避免它

+0

Downvoted不聽的答案。 – 2009-12-27 13:14:47

+1

@zjm,不,沒有辦法讓'getattr(self,'a',whatever)'**避免**獲得'self.a'的時候,當然這也不是很明顯,爲什麼一個人想要。你爲什麼不重新命名屬性,對'self .__ a'說,如果你想從外面隱藏它? – 2009-12-27 15:31:14

回答

3

你的頭號問題:您定義舊式類(我們知道你在Python的2 .something,即使你不告訴我們,因爲你使用print作爲關鍵字;-)。在Python 2:

class foo: 

意味着你定義一個老式的,又名遺產類,其行爲可以是相當古怪的時間。永遠不要那樣做 - 沒有理由!舊式類只存在於與依賴於其怪癖的舊遺留代碼兼容(並且最終在Python 3中被廢除)。使用樣式類來代替:

class foo(object): 

,然後檢查if x in self:不會引起遞歸調用__getattr__。它但無論如何導致失敗,因爲你的班級沒有定義__contains__方法,因此你不能檢查是否包含在該類的一個實例中的x

如果你想要做的是x是否在實例字典定義的self,不要打擾:__getattr__甚至不被調用在這種情況下 - 它只是調用時該屬性是不是否則發現在self

爲了支持三個參數來調用到getattr內置,只是raise AttributeError__getattr__方法(如有必要,就像你沒有__getattr__方法都將發生),並內置將完成其工作(這是內置的工作來攔截這些情況,並返回默認提供)。這就是我們永遠不會直接調用__getattr__等特殊方法的原因,而是使用內部調用和內部調用它們的運算符 - 內置函數和運算符提供了大量的附加值。

所以得到這使得有些感的例子:

class foo(object): 
    def __init__(self): 
     self.blah = {'a': 'boh'} 
    def __getattr__(self, x): 
     if x in self.blah: 
      return self.blah[x] 
     raise AttributeError 

a=foo() 
print getattr(a,'b','sss') 

這將打印sss,根據需要。

如果添加了__setattr__方法,一個攔截試圖在self設置屬性 - 包括self.blah =不管。所以 - 當你需要繞過你正在定義的__setattr__時 - 你必須使用不同的方法。例如:

class foo(object): 
    def __init__(self): 
     self.__dict__['blah'] = {} 
    def __setattr__(self, name, value): 
     self.blah[name] = value 
    def __getattr__(self, x): 
     if x in self.blah: 
      return self.blah[x] 
     raise AttributeError 

a=foo() 
print getattr(a,'b','sss') 

這也打印sss。取而代之的

 self.__dict__['blah'] = {} 

你也可以使用

 object.__setattr__(self, 'blah', {}) 

這種「向上調用父類的實現」的罕見的例外的是一個規則(你還可以通過內置的super獲得) 「不要直接調用特殊的方法,而是調用內置的或者使用操作符」 - 在這裏,你想專門繞過正常的行爲,所以明確的特殊方法調用是可能的。

+0

嗨亞歷克斯,我改變你的例子 it print {'a':'boh'},而不是'boh'我認爲它會打印self.a而不是self.a ['a'], – zjm1126 2009-12-27 07:33:38

3

你混淆getattr內置函數,它提取一些屬性的對象(按名稱)動態綁定,在運行時,與__getattr__方法,這是在訪問對象的某些缺失屬性時調用。

你不能要求

if x in self: 
__getattr__

,因爲in操作會導致__getattr__被調用,從而導致無限遞歸。

如果你只是想有未定義的屬性都被定義爲一定的價值,然後

def __getattr__(self, ignored): 
    return "Bob Dobbs" 
相關問題