2017-10-19 134 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'>