2017-10-19 15 views
4

私はすべてのユーザー定義の__slots__属性のリストを返すはずの私の基底クラスに__dir__カスタム実装を持っています。これは一般的に動作していますが、返す前に結果に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__()の出力には、芋、同一であるべきです。

ではなく、この問題が発生した:dir()を使用した場合

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

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

私はの種類は、それがアルファベット順に出力をソートすることを理解することができます - これはdocumented in the docsです。しかし、それはカスタムの__dir__メソッドを定義していても出力をソートするというバグのように見えます。

2番目の出力は、ゲームを完全にオフにします。 dirは、コードが同一であるがslots()を呼び出すと重複した値を返すので、出力の重複を避けるために、何らかのフィルタを使用しています(おそらくset)。

私はどちらもA)なぜそれが最初に起こるのか理解していないし、B)何が地球上でdirがやっているのか理解していない。

ここにはどのようなポインタがありますか?

編集: - したがって、そのクラスが二度含まれている
後者の場合は__mro__ solved-では、呼び出し側のクラスだけでなく、それはから継承するすべてのクラスが含まれています。 すなわち:

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

これは__dir__が実装される前から、Cのソースコードから発信何かのように見える:コメントで参照さの問題は、この動作のソースにほんの少しより多くの光を当てます。

編集3:
私はissue on python's bug trackerを開きました。コンセンサスが何であるか見てみましょう。しかし、私はこれがbackburnerに置かれることを期待しています(もしあれば)dir()は、主にIDLEなどの検査のために設計されたものです。

+0

すべての非ユニークな要素は、削除されます。 'dir'はあなたのカスタムメソッドを呼び出していますが、それを後処理してドキュメンテーションをコンパイルします。 –

+0

実際、idはそれらを削除しません - 私はちょうどそれをテストし、それもそれらを保持します。私は 'F'から' __slots__'を2回追加していました。 – nlsdfnbch

+0

これは予期しない動作のようです。 'dir()'が '__dir __()'を呼び出すなら、私はそれが私の言うとおりにすると期待しています。 – nlsdfnbch

答えて

1

issue opened on the Python bug trackerあたりとして:あなたがPythonで同じ名前のメソッドにアクセスすることができないため、

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'> 
関連する問題