27

この質問は、 について__dir__よりも多くのことを意図していますnumpy

numpy.recarray(python 2.7、numpy 1.6.2 で)のサブクラスがあり、オブジェクトを ing するrecarrayときに のフィールド名がリストされていないことに気付きdirました (したがって、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__'. (ここで、これは実際には python 3.3 で動作するはずであることがわかりました...)

回避策として、私は試しました:

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

私が知る限り、これは機能しますが、もちろん、エレガントではありません。

質問:

  1. 私の場合、つまりのサブクラスの場合、後者の解決策は正しいrecarrayですか?
  2. 一般的なケースで機能させる方法はありますか?多重継承 (-call チェーンを壊す) では機能しないように思えます。superもちろん、オブジェクトの場合は__dict__...
  3. recarrayそもそもなぜがフィールド名のリストをサポートしていないのか知っていますか? ただの見落とし?
4

3 に答える 3

6

サブクラスでの__dir__メソッドの実装を簡素化する Python 2.7+、3.3+ クラス mixin 。それが役立つことを願っています。要点

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)
于 2015-09-08T08:46:08.913 に答える
3
  1. そして3:はい、あなたの解決策は正しいです。は、デフォルトの実装が問題ないという理由だけでrecarray定義されていないため、実装する必要がなく、開発者はクラスをサブクラス化するように設計していないため、なぜ気にする必要があるのか​​ わかりません。__dir__numpy

    継承のために特別に設計されていない組み込み型またはクラスをサブクラス化することはしばしば悪い考えです。numpyで明示的にチェックする関数にisinstance)。

  2. いいえ。あなたが python3 で指摘したように、彼らは実装を変更して が存在するようにしましたobject.__dir__が、他の python バージョンでは、あなたができることは何も見えません。また、繰り返しますが、recarray複数の継承を使用するのは単純にクレイジーです。物事壊れます。多重継承は慎重に設計する必要があり、通常、クラスは多重継承で使用するように特別に設計されています (例: ミックスイン)。したがって、このケースを処理しようとする人は誰でも他の問題に悩まされるため、わざわざこのケースを処理するつもりはありません。

    持っていないクラスを気にする必要がある理由がわかりません__dict__...あなたのサブクラスにはそれがあるので、どのように壊す必要がありますか? サブクラスの実装を変更する場合、たとえば使用__slots__すると、簡単に変更すること__dir__もできます。再定義を避けたい場合は、 thenなど__dir__をチェックする関数を定義するだけです。ただし、属性はandを使用して微妙な方法で生成できるため、すべてを確実にキャッチすることはできないことに注意してください。__dict____slots____getattr____getattribute__

于 2013-03-20T16:27:44.643 に答える