27

这个问题的意思是__dir__比 about更多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. 有没有办法让它在一般情况下工作?在我看来,它不适用于多重继承(打破super-call 链),当然,对于没有__dict__...的对象
  3. 你知道为什么recarray不支持列出它的字段名开头吗?仅仅是疏忽?
4

3 回答 3

6

Python 2.7+、3.3+ 类 mixin,简化了子类中__dir__方法的实现。希望它会有所帮助。要点

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 回答
4

你有没有尝试过:

def __dir__(self):
    return sorted(set(
               dir(super(MyRecArray, self)) + \
               self.__dict__.keys() + self.dtype.fields.keys()))
于 2017-10-29T12:02:49.713 回答
3
  1. 和 3:是的,您的解决方案是正确的。recarray没有定义__dir__仅仅因为默认实现是好的,所以他们没有费心去实现它,而且numpy's 的开发人员没有设计要子类化的类,所以我不明白他们为什么应该打扰。

    子类化内置类型或不是专门为继承而设计的类通常是一个坏主意,因此我建议您使用委托/组合而不是继承,除非有特殊原因(例如,您想传递它到一个numpy用 ) 明确检查的函数isinstance

  2. 不。正如您在 python3 中指出的那样,他们更改了实现,以便有一个object.__dir__,但在其他 python 版本上,我看不到您可以做的任何事情。同样,使用recarray多重继承简直是疯狂的,事情破裂。应该仔细设计多重继承,并且通常专门设计类来与它一起使用(例如混合)。所以我不会费心处理这个案例,因为任何尝试它的人都会被其他问题所困扰。

    我不明白为什么你应该关心没有的类__dict__......因为你的子类有它应该如何打破?当您更改子类实现时,例如使用__slots__您也可以轻松更改__dir__。如果您想避免重新定义__dir__,您可以简单地定义一个检查__dict__then for__slots__等的函数。但是请注意,属性可以通过微妙的方式生成,__getattr__因此__getattribute__您根本无法可靠地捕获所有这些属性。

于 2013-03-20T16:27:44.643 回答