2013-03-19 95 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()))