2013-03-19 3 views
21

pythonで__ DIR__メソッドをオーバーライドするための正しい方法。この質問を、約<code>numpy</code>より<code>__dir__</code>詳細であることを意味する

は、私が(のpython 2.7、numpyの1.6.2で)numpy.recarrayのサブクラスを持っている、と私はdirは(したがって、ipythonのオートコンプリートが動作しません)オブジェクトをINGの際recarrayのフィールド名が表示されていません気づきました。

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

をもたらした:AttributeError: 'super' object has no attribute '__dir__'それを修正しようと

は、私はこのように、私のサブクラスで__dir__をオーバーライドしてみました。 は、回避策として

を(私はこれは実際には...のpython 3.3で動作するはずhereを見つけました)、私が試した:

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

を私の知る限り、これは動作しますが、もちろん、ありませんエレガントに。

質問:

  1. 後者の解決策は、すなわちrecarrayのサブクラスのために、私の場合は正しいですか?
  2. 一般的なケースで動作させる方法はありますか?それは複数の継承(super -callチェーンを破って)で動作しないと思われます。もちろん、__dict__のオブジェクトではありません。
  3. は、開始するフィールド名のリストをサポートしていませんと?単なる見落としですか?
+0

を私は 'recarray'と' dir'をサブクラス化してみました** ** 'recarray'の属性を示しています。あなたは何が欠けていると思いますか? – Bakuriu

+0

'self.dtype.fields.keys()' – shx2

答えて

3

のPython 2.7以降のサブクラスで__ DIR__方法の実装を簡素化し、3.3+クラスミックスイン。それが助けてくれることを願って。 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年代の開発者は、サブクラス化するクラスを設計していなかったので、彼らは気にしている必要があり、なぜ私は表示されません。

    継承のために特別に設計されていない組み込み型やクラスをサブクラス化することはよくありませんので、継承の代わりに委譲/合成を使用することをお勧めします。間違ってisinstanceでチェックするnumpy関数に渡したいとします。

  2. いいえ、python3で指摘したように、彼らはobject.__dir__があるように実装を変更しましたが、他のPythonのバージョンでは私はあなたができることは何も見えません。また、再度、recarrayを複数の継承で使用すると、単に狂気になります。になります。多重継承は慎重に設計されなければならず、通常クラスはそれと共に使用するように特別に設計されています(例えば、ミックスイン)。だから私はこの事件を処理しようとする人は誰もが他の問題に噛まれるので、気にしないだろう。あなたは、サブクラスがそれを持っているので、それがどのようにを破る必要があります... __dict__を持たないクラスの世話をすべき理由

    私は表示されないのですか?あなたがサブクラスの実装を変更するとき、例えば。 __slots__を使用すると、__dir__も簡単に変更できます。あなたが__dir__を再定義しないようにしたい場合は、単に__getattr____getattribute__との微妙な方法で生成することができる属性が__slots__など注意するために、その後__dict__をチェックする関数を定義することができますので、あなたは単には確実にそれらのすべてをキャッチすることはできません。

+1

詳細な回答ありがとうございます。私は複数の継承についてあなたの意見を受け入れる。私の質問#2では、私は一般的なケースでは、次の擬似コードを実装する最良の方法について質問しています: 'return dir_listing(my_super_object)+ specific_dir_listing(self)'。私のスーパークラスが '__getattr__'をオーバーライドすると、私は' __dir__'を正しくオーバーライドすることに頼ります。私のサブクラスがそうであれば、私はその部分を 'specific_dir_listing(self)'に含めます。問題はそれらをフェッチする方法です。 – shx2

1

あなたが試してみました:

def __dir__(self): 
    return sorted(set(
       dir(super(MyRecArray, self)) + \ 
       self.__dict__.keys() + self.dtype.fields.keys())) 
関連する問題