custom __dir __()返回按字母顺序排序的属性列表

时间:2017-10-19 07:13:56

标签: python python-3.x python-3.5 built-in slots

我的基类中有一个自定义__dir__实现,它应该返回所有用户定义的__slots__属性的列表。一般情况下,这是有效的,但它似乎在结果返回之前对结果进行了sort,即使我没有编程来执行此操作(我需要属性以完全相同的顺序,他们'重新分配)。

一个例子:

class A:
    __slots__ = ['b', 'a']

    def __dir__(self):
        slot_attrs = []
        for parent_class in reversed(type(self).__mro__[:-1]):
            for attr in parent_class.__slots__:
                slot_attrs.append(attr)
        for attr in self.__slots__:
            slot_attrs.append(attr)
        return slot_attrs


class B(A):
    __slots__ = ['c', 'd']
    pass


class C(B):
    __slots__ = []
    pass


class D:
    __slots__ = ['b', 'a']

    def slots(self):
        slot_attrs = []
        for parent_class in reversed(type(self).__mro__[:-1]):
            for attr in parent_class.__slots__:
                slot_attrs.append(attr)
        for attr in self.__slots__:
            slot_attrs.append(attr)
        return slot_attrs


class E(D):
    __slots__ = ['c', 'd']
    pass


class F(E):
    pass

slots()__dir__()的输出应该是,imo,相同。

但相反,会发生这种情况:

>>>c = C()
>>>f = F()

>>>print(dir(c))
['a', 'b', 'c', 'd']
>>>print(f.slots())
['b', 'a', 'c', 'd', 'c', 'd', 'c', 'd']

有点了解它在使用dir()时按字母顺序对输出进行排序 - 这是documented in the docs。但是,即使我已经定义了自定义__dir__方法,它看起来像是一个错误 - 或者至少是我意外的行为 - 它对输出进行排序。

第二个输出完全让我完全放弃了我的游戏。它表明dir也使用某种过滤器,可能是set以避免重复输出,因为代码相同但调用slots()会返回重复值。

我既不是A)理解为什么它首先这样做,也不是B)dir到底是做什么的。

这里有指针吗?

修改
第二种情况得到解决 - __mro__包含调用者的类,以及它继承的所有类 - 因此该类包含两次。 即:

>>>F.__mro__
(<class '__main__.F'>, <class '__main__.E'>, <class '__main__.D'>, <class 'object'>)

编辑2:
情节变粗。评论中提到的问题对这种行为的来源有了更多的了解:

>>Couldn't __dir__ also be allowed to return a tuple?
no, because tuples are not sortable, and i don't want to 
over complicate the c-side code of PyObject_Dir. 
having __dir__ returning only a list is equivalent to 
__repr__ returning only strings.

这似乎是源自C源代码的内容,从__dir__实现之前开始。

编辑3:
我打开了issue on python's bug tracker。让我们看看共识是什么。但是,我希望这会被放在后面(如果有的话),因为dir()是afaik,主要用于IDLE等的检查。

1 个答案:

答案 0 :(得分:1)

根据issue opened on the Python bug tracker

https://docs.python.org/3/library/functions.html#dir also states that "The resulting list is sorted alphabetically." The section has an example where __dir__ returns an unsorted list but dir() returns a sorted list:

            class Shape:

...     def __dir__(self):
...         return ['area', 'perimeter', 'location']

            s = Shape()
            dir(s)

['area', 'location', 'perimeter']

Since the primary purpose of dir() is convenient use for humans, sorting makes perfectly sense. If you need tight control over order of values, you should make your object iterable instead or provide another method.

Several dunder methods perform some sort of post-processing or post-check:

            class Example:

...     def __bool__(self): return 2
...

            bool(Example())

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __bool__ should return bool, returned int

            class MyInt(int):

...     pass
...

            type(MyInt(1))

<class '__main__.MyInt'>

            class Example:

...     def __int__(self):
...         return MyInt(1)
...

            int(Example())

1

            type(int(Example()))

<class 'int'>