2017-10-19 69 views
4

我在我的基类的自定义__dir__实现其应该返回所有用户定义__slots__属性的列表。一般来说,这是行得通的,但它似乎在返回结果前对结果做了sort,尽管我没有编程去实现这一点(我需要按照它们分配完全相同的顺序的属性)。定制__dir __()返回排序的属性列表按字母顺序

一个例子:

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__()输出应,伊莫相同。

而是出现这种情况:

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

我既不知道为什么它首先做到这一点,也没有B)dir究竟是在做什么。

任何指针?

编辑
第二种情况是solved- __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等的检测。

+0

所有非独特的元素被删除,因为你不能访问在python的同名方法。 'dir'只是调用你的自定义方法,但后处理它是对文档的编译。 –

+0

实际上,id不会将它们删除 - 我只是对它进行了测试,它也保留了它们。我只是从'F'加了'__slots__'两次。 – nlsdfnbch

+0

它似乎仍然是意想不到的行为。如果'dir()'调用'__dir __()',那么我希望它可以像我说的那样去做,而不是在它之上做一些幕后的巫术。 – nlsdfnbch

回答

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'>