【问题标题】:What is the correct way to override the __dir__ method?覆盖 __dir__ 方法的正确方法是什么?
【发布时间】:2013-03-08 14:53:53
【问题描述】:

这个问题更多的是关于__dir__,而不是numpy

我有一个numpy.recarray 的子类(在python 2.7 中,numpy 1.6.2),我注意到recarray 的字段名称在diring 对象时没有列出(因此 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-call 链),当然,对于没有__dict__的对象...
  3. 你知道为什么recarray 不支持列出它的字段名开头吗?仅仅是疏忽?

【问题讨论】:

  • 我试图继承 recarraydir 确实显示 recarray 属性。你能解释一下你认为缺少什么吗?
  • self.dtype.fields.keys()

标签: python inheritance python-2.7 introspection


【解决方案1】:

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)

【讨论】:

    【解决方案2】:

    你试过了吗:

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

    【讨论】:

    • 我一定忽略了这个答案。这是正确的答案。现已接受。
    • @shx2 这包括super 对象独有的属性,不包括对象的方法。
    【解决方案3】:
    1. 和 3:是的,您的解决方案是正确的。 recarray 没有定义 __dir__ 只是因为默认实现没问题,所以他们没有费心去实现它,而 numpy 的开发人员没有设计要子类化的类,所以我不明白他们为什么应该打扰了。

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

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

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

    【讨论】:

    • 感谢您的详细回答。我接受你关于多重继承的观点。在我的问题 #2 中,我问的是在一般情况下实现以下伪代码的最佳方法:return dir_listing(my_super_object) + specific_dir_listing(self)。如果我的超类覆盖__getattr__,我依靠它来正确覆盖__dir__。如果我的子类有,我会将该部分包含在specific_dir_listing(self) 中。问题是如何获取它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    • 2023-03-15
    • 1970-01-01
    • 2012-05-14
    • 2019-05-04
    • 2020-07-22
    • 1970-01-01
    相关资源
    最近更新 更多