2016-02-10 21 views
9

次のコードは、Python 2とPython 3では動作が異なりますが、その理由はわかりません。Python 2と3の "dir"の相違点

class Dataset(object): 
    def __getattr__(self, item): 
     if not item in dir(self): 
      print(item) 

a = Dataset() 
a.Hello 

のPython 3での結果:

> Hello 

のPython 2での結果:再帰天井に到達するまで

__members__ 
__members__ 
__methods__ 
... 

無限。 "dir"の動作の違いは何ですか?

編集:回避策はありますか?自己。 dictは明らかな選択ですが、私のコードでは問題となる機能は含まれていません。

+2

としてあなたのコードを持つことができ (自己)と呼ばれないことを確認するために必要ではないです属性が既に存在する場合、 '__getattr __()' [[呼び出されることはまったくありません]](https://docs.python.org/2/reference/datamodel.html#object.__getattr__)です。 – dhke

答えて

6

のPython 2.7でdirのドキュメント3.5は同じように見える - 実装の詳細はない。しかし明らかに、Python 2のdir()は、無限再帰を引き起こす__getattr__を呼び出します。

しかし、両方のマニュアルセットは

ので()は対話プロンプトでの使用に便利なように主に供給されているディレクトリ、それが提供しようとするよりも多くの名前の興味深いセットを供給しようと言うん厳密にまたは一貫して定義された名前セットであり、その詳細な動作はリリース間で変更される可能性があります。たとえば、引数がクラスの場合、メタクラス属性は結果リストにありません。

便宜的には注意が必要です。

あなたが代わりにdir()を使用してのself.__dict__を見て、あなたの__getattr__を変更した場合、問題が消えます。

In [5]: class Dataset(object): 
      def __getattr__(self, item): 
      if not item in self.__dict__: 
       print(item) 
    ...:    

In [6]: a = Dataset() 

In [7]: a.Hello 
Hello 
+1

答えが – kdopen

+1

のAFAIRを投稿してから、 'dir()'が '__dir__'を検索しようとするまで、関数の編集は見られませんでした。それが存在しないので、 '__getattr __()'が呼び出されます。これは 'dir()'を呼びます... – dhke

3

ソースコードを調べなければ、私が言うことができない理由この問題が発生した(私はいくつかの仮説を持っているが)が、ここでは非常に単純な回避策は次のとおりです。

class Dataset(object): 
    def __getattr__(self, item): 
     try: 
      super(Dataset, self).__getattr__(item) 
     except AttributeError: 
      print(item) 
1

アイテムがディレクトリに表示されている場合if not item in dir(self)__getattr__

def __getattr__の内側には、あなたが実際に

class Dataset(object): 
    x = 12 
    def __getattr__(self, item): 
     print(item) 

a = Dataset() 
a.Hello # print Hello 
a.x  # return 12