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

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

一个例子:

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也使用某种过滤器,也许是一组避免重复输出,因为代码是相同的但调用slots()会返回重复值.

我既没有A)理解为什么它首先这样做,也不是B)地球上的什么在做什么.

这里有什么指示?

编辑:
第二种情况得到解决 – __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.让我们看看共识是什么.但是,我希望这将被放在backburner上(如果有的话),因为dir()是afaik,主要用于IDLE等的检查.

最佳答案 根据
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'>
点赞