2013-02-04 99 views
0

我不得不寫一些類別,覆蓋__getattribute__。 基本上我的課是一個容器,它將每個用戶添加的屬性保存到self._meta這是一本字典。蟒蛇__getattribute__覆蓋和@property裝飾

class Container(object): 
    def __init__(self, **kwargs): 
     super(Container, self).__setattr__('_meta', OrderedDict()) 
     #self._meta = OrderedDict() 
     super(Container, self).__setattr__('_hasattr', lambda key : key in self._meta) 

     for attr, value in kwargs.iteritems(): 
      self._meta[attr] = value 

    def __getattribute__(self, key): 
     try: 
      return super(Container, self).__getattribute__(key) 
     except: 
      if key in self._meta : return self._meta[key] 
      else: 
       raise AttributeError, key 

    def __setattr__(self, key, value): 
     self._meta[key] = value 
#usage: 
>>> a = Container() 
>>> a 
<__main__.Container object at 0x0000000002B2DA58> 
>>> a.abc = 1 #set an attribute 
>>> a._meta 
OrderedDict([('abc', 1)]) #attribute is in ._meta dictionary 

我有一些類繼承Container基類,他們的一些方法有@property裝飾器。

class Response(Container): 
    @property 
    def rawtext(self): 
     if self._hasattr("value") and self.value is not None: 
      _raw = self.__repr__() 
      _raw += "|%s" %(self.value.encode("utf-8")) 

      return _raw 

問題是.rawtext無法訪問。 (我得到了attributeerror。)._meta中的每個鍵都是可訪問的,基類的__setattr____setattr__添加的每個屬性都是可訪問的,但通過@property裝飾器的方法對屬性不是。我認爲這與我在Container基類中重寫__getattribute__的方式有關。我應該怎樣做@property的房產?

+2

你真的需要* *使用'__getattribute__',而不是'__getattr__'? – mgilson

+0

@mgilson我如何處理'__getattr__'? – thkang

+0

只有在實例上未找到該屬性時纔會調用__getattr__'。 – Bakuriu

回答

6

我想你應該考慮看__getattr__而不是__getattribute__這裏。不同之處在於:__getattribute__如果存在,將被無條件地調用 - __getattr__僅在python無法通過其他方式找到該屬性時調用。

+0

我明白了,所以我不應該觸摸'__getattribute__'並只修改'__getattr__'來讓python協議完成這項工作? – thkang

+0

@thkang - 這就是我提出的,是的:)。用你的'__setattr__'這個樣子,它應該做我認爲正確的事情。 (一世。e,它應該將屬性包含到元命令字典中,但仍然會允許屬性和方法!在子類上) – mgilson

2

我完全同意mgilson。如果你想這應該是等同於你的代碼示例代碼,但與性工作以及你可以試試:

class Container(object): 
    def __init__(self, **kwargs): 
     self._meta = OrderedDict() 
     #self._hasattr = lambda key: key in self._meta #??? 
     for attr, value in kwargs.iteritems(): 
      self._meta[attr] = value 

    def __getattr__(self, key): 
     try: 
      return self._meta[key] 
     except KeyError: 
      raise AttributeError(key) 

    def __setattr__(self, key, value): 
     if key in ('_meta', '_hasattr'): 
      super(Container, self).__setattr__(key, value) 
     else: 
      self._meta[key] = value 

我真的不明白你_hasattr屬性。你把它作爲一個屬性,但它實際上是一個功能,可以訪問self ...不應該是一種方法? 其實我覺得你應該使用簡單的內置函數hasattr

class Response(Container): 
    @property 
    def rawtext(self): 
     if hasattr(self, 'value') and self.value is not None: 
      _raw = self.__repr__() 
      _raw += "|%s" %(self.value.encode("utf-8")) 

      return _raw 

注意hasattr(container, attr)將返回True也爲_meta

讓我感到困惑的另一件事是爲什麼你使用OrderedDict。我的意思是,你迭代kwargs,迭代具有隨機順序,因爲它是一個正常的dict,並在OrderedDict中添加項目。現在你有_meta其中包含隨機順序的值。 如果您不確定是否需要特定訂單,只需使用dict,並最終在以後換成OrderedDict

順便說一句:從來沒有有史以來使用try: ... except:沒有指定例外捕獲。在你的代碼其實是想只捕獲AttributeError這麼你應該做的:

try: 
    return super(Container, self).__getattribute__(key) 
except AttributeError: 
    #stuff 
+0

+1 - 很好的工作清理OP的代碼。 – mgilson

+0

感謝您的努力。我看到你對kwargs的觀點 - 我錯過了一些關鍵的東西。如您所說,不需要kwargs:D – thkang

+0

問題 - 如何在這裏實現刪除方法? – viksit