Pythonにおいて、あるオブジェクトに備わっている属性を調べる際に使用する関数としてdir関数とhasattr関数があるかと思いますが、
「dir関数の実行結果には出力されないが、hasattr関数ではTrueになる」
という事象に関して質問があります。
事象の例
たとえば__builtins__に__dict__属性がある調査したいとき、hasattr関数を使用すると「True」が返ってきます。
※Pythonのバージョンは3.9です。
Python
1#Trueと出力される2print(f'{hasattr(__builtins__,"__dict__")=}')
しかし、__builtins__に対してdir関数を実行した場合、出力結果に__dict__は存在しません。
Python
1#出力結果に__dict__は存在しない2print(f'{dir(__builtins__)=}')
実際に__builtins__から__dict__属性を参照することはできるため、hasattr関数の結果の方が正しいかと思います。
Python
1#問題なく参照できる2print(f'{__builtins__.__dict__=}')
お聞きしたいこと
この事象について2点お聞きしたいことがあります。
【質問1】dir関数は、実行結果として「そのオブジェクトに備わっているすべての属性を出力するとは限らない」という認識でよいのでしょうか。
__builtins__は、以下のコードの結果から__dir__()というメソッドを持つかと思います。
Python
1#Trueが返ってくる2print(f'{hasattr(__builtins__,"__dir__")=}')3 4#エラーにならず呼び出し可能5print(__builtins__.__dir__())
公式ドキュメントにて、dir関数の項目には
オブジェクトが
__dir__()という名のメソッドを持つなら、そのメソッドが呼び出され、属性のリストを返さなければなりません。これにより、カスタムの__getattr__()や__getattribute__()関数を実装するオブジェクトは、dir() が属性を報告するやり方をカスタマイズできます。
とあり、また、
dir()は主に対話プロンプトでの使用に便利なように提供されているので、厳密性や一貫性を重視して定義された名前のセットというよりも、むしろ興味を引くような名前のセットを返そうとします。また、この関数の細かい動作はリリース間で変わる可能性があります。例えば、引数がクラスであるとき、メタクラス属性は結果のリストに含まれません。
とあります。
これらの記述から、今回例に挙げた__builtins__が__dict__属性を備えているか否かについては
①__builtins__オブジェクトは__dict__属性を備えている
②dir関数は引数に与えられたオブジェクトのが備えるすべての属性を出力するとは限らずない
③__builtins__をdir関数の引数に与えて実行したとき、__dict__属性は②の例に該当し、出力されなかった。
という認識でよいのでしょうか。
【質問2】とあるオブジェクトが備える属性を確認したいときにベストな手法について
今回の__builtins__に対するhasattr関数とdir関数の挙動からすると、とあるオブジェクトが備える属性を確認したいときにはhasattr関数の方がより確実な結果を得ることができるように見えるのですが、実際のところはどうなのでしょうか。
また、もしもhasattr関数の方がdir関数よりより確実な結果を得ることができたとしても、さらにhasattr関数より良い関数や手法があるのでしょうか。
詳しい方、教えていただけますと幸いです。
よろしくお願いいたします。

0 コメント