2013-03-19 78 views
21

此問題旨在更多地關於__dir__而不是約numpy覆蓋python中__dir__方法的正確方法

我有numpy.recarray(在Python 2.7,numpy的1.6.2)一個子類,我注意到recarraydir荷蘭國際集團的對象(因此IPython中的自動完成不工作)的字段名稱未列出。

試圖修復它,我想在我的子類覆蓋__dir__,像這樣:

def __dir__(self): 
    return sorted(set(
       super(MyRecArray, self).__dir__() + \ 
       self.__dict__.keys() + self.dtype.fields.keys())) 

導致用:AttributeError: 'super' object has no attribute '__dir__'。 (我發現here這應該在Python 3.3的實際工作...)

作爲一種變通方法,我想:

def __dir__(self): 
    return sorted(set(
       dir(type(self)) + \ 
       self.__dict__.keys() + self.dtype.fields.keys())) 

據我所知,這一個工作,但當然不是作爲優雅。

問題:

  1. 是後者的解決方案在我的情況是正確的,即對於recarray一個子類?
  2. 有沒有辦法讓它在一般情況下工作?在我看來,它不適用於多繼承(打破super-呼叫鏈),當然,對於沒有__dict__的對象...
  3. 你知道爲什麼recarray不支持列出其字段名稱以開始用?僅僅是疏忽?
+0

我試圖子類'recarray'和'dir' ** **不顯示'recarray'屬性。你能解釋一下你認爲錯過了什麼嗎? – Bakuriu 2013-03-19 19:35:19

+0

'self.dtype.fields.keys()' – shx2 2013-03-20 14:48:09

回答

3

的Python 2.7+,3.3+類混入,它簡化了實施在子類__DIR__方法。希望它會有所幫助。 Gist

import six 
class DirMixIn: 
    """ Mix-in to make implementing __dir__ method in subclasses simpler 
    """ 

    def __dir__(self): 
     if six.PY3: 
      return super(DirMixIn, self).__dir__() 
     else: 
      # code is based on 
      # http://www.quora.com/How-dir-is-implemented-Is-there-any-PEP-related-to-that 
      def get_attrs(obj): 
       import types 
       if not hasattr(obj, '__dict__'): 
        return [] # slots only 
       if not isinstance(obj.__dict__, (dict, types.DictProxyType)): 
        raise TypeError("%s.__dict__ is not a dictionary" 
            "" % obj.__name__) 
       return obj.__dict__.keys() 

      def dir2(obj): 
       attrs = set() 
       if not hasattr(obj, '__bases__'): 
        # obj is an instance 
        if not hasattr(obj, '__class__'): 
         # slots 
         return sorted(get_attrs(obj)) 
        klass = obj.__class__ 
        attrs.update(get_attrs(klass)) 
       else: 
        # obj is a class 
        klass = obj 

       for cls in klass.__bases__: 
        attrs.update(get_attrs(cls)) 
        attrs.update(dir2(cls)) 
       attrs.update(get_attrs(obj)) 
       return list(attrs) 

      return dir2(self) 
3
  1. 和3:是你的解決方案是正確的。 recarray沒有定義__dir__,只是因爲默認的實現是好的,所以他們沒有打擾實現它,並且numpy的開發人員沒有設計類的子類,所以我不明白爲什麼他們應該打擾。

    對於並不專門爲繼承設計的內置類型或類進行子類化通常是一個壞主意,因此我建議您使用委託/組合而不是繼承,除非有特定的原因(例如,您想要將它傳遞給numpy函數,該函數用isinstance進行明確檢查)。

  2. 不會。正如你在python3中指出的那樣,他們改變了實現,以便有object.__dir__,但在其他python版本中,我看不到任何你可以做的事情。另外,再次使用帶有多重繼承的recarray簡直是瘋狂,事情將會破。應該仔細設計多重繼承,並且通常類是專門設計用於與它一起使用的(例如混合)。所以我不會理睬這個案子,因爲試過它的人會被其他問題困住。

    我不明白你爲什麼應該關心沒有__dict__的類......因爲你的子類有它,它應該如何中斷?當你改變子類的實現時,例如使用__slots__您也可以輕鬆更改__dir__。如果你想避免重新定義__dir__你可以簡單地定義,對於__dict__檢查然後但__slots__等注意這些屬性可以與__getattr____getattribute__微妙的方式來產生一個功能,因此你根本不能可靠地捕獲所有他們的。

+1

感謝您的詳細解答。我接受你關於多重繼承的觀點。在我的問題2中,我詢問了一般情況下最好的方法來實現下面的僞代碼:'return dir_listing(my_super_object)+ specific_dir_listing(self)'。如果我的超類覆蓋'__getattr__',我依靠它正確地覆蓋'__dir__'。如果我的子類有,我將這部分包含在'specific_dir_listing(self)'中。問題是如何獲取它們。 – shx2 2013-03-20 17:41:14

1

你試過:

def __dir__(self): 
    return sorted(set(
       dir(super(MyRecArray, self)) + \ 
       self.__dict__.keys() + self.dtype.fields.keys()))