2016-01-05 20 views
5

ユーザー定義のPythonicクラスについて考えてみましょう。組み込み関数の変更

['__class__', '__delattr__', '__dict__', '__dir__', ... '__weakref__', 'bases', 
'build_full_name', 'candidates', ... 'update_name']. 

あなたはこのリスト内の属性の2種類を見ることができます:

  • 組み込み属性、定義された
  • ユーザー私はdir(obect_of_class)を呼び出すと、私はその属性のリストを取得します。

__dir__を無効にする必要があります。つまり、ユーザー定義のattribltesだけが返されます。私はそれをどのようにすることができますか?

オーバーライドされた関数で自分自身を呼び出すと、無限の再帰が得られることは明らかです。だから、私はこのようにsomethigをしたい:

def __dir__(self): 
     return list(filter(lambda x: not re.match('__\S*__', x), dir(self))) 

しかし、無限の再帰を回避する。

一般に、最初から書き込むのではなく、既存の関数を変更したい場合、どのように組み込み関数を変更できますか?

+0

代わりに 'dir(ClassName)'を使ってみましたか? – DainDwarf

答えて

8

superを使用して、親の実装__dir__を呼び出します。再帰を避ける:

import re 


class AClass: 

    def __dir__(self): 
     return [x for x in super().__dir__() if not re.match(r'__\S+__$', x)] 

    def method(self): 
     pass 

>>> dir(AClass()) 
['method'] 
+0

ジェネレータを使用する方が 'list(filter ...) 'を使うよりも良いのはなぜですか? – VeLKerr

+1

@VeLKerr、それはジェネレータではなく、リストの理解です。私にとっては、読むのがずっと簡単です。 – falsetru

+0

これはうまくいっていますが、 'super()' -objectにユーザ定義のフィールドがないため、非常に奇妙です。だから、あなたは説明することができますか?*なぜ*働いていますか? – VeLKerr

2

あなたはdir()機能に対してグローバルカスタムクラスでそれを行うか、しますか?

ファーストアプローチ(クラスのみ):

class MyClass: 
    def f(self): 
     return None 

    def __dir__(self): 
     return list(filter(lambda x: not re.match('__\S*__', x), super().__dir__())) 


print(dir(MyClass())) # ['f'] 

は基本的にここで行われているもの(ないクラス自体)スーパークラスの__dir__()を呼び出し、サブクラスでそれをフィルタリングしています。

(グローバルDir関数をシャドウイング)第二のアプローチ:dir()にここ

import re 


def dir(obj): 
    return list(filter(lambda x: not re.match('__\S*__', x), __builtins__.dir(obj))) 

print(dir({})) # ['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] 

すべてのコールがフィルタリングされます。ご覧のように、組み込み型を含むすべての型で動作します。

+0

自分のクラスに対してのみ '__dir()__'をオーバーライドしたいですが、グローバルシャドウイングの説明にはとても感謝しています。 P.S. 'super()'は引数なしでも私のために働きます(私は投稿を編集しました)。 – VeLKerr

関連する問題