はてブロ@ama_ch

https://twitter.com/ama_ch

組み込み関数dir()をカスタマイズする

「初めてのPython」p.344に載っていたdir()のような動作をするソースがなかなか良い感じです。

#!usr/bin/env python
# -*- coding: utf-8 -*-
""" mydir.py
組み込み関数dir()をカスタマイズする例
指定のモジュールの名前空間に属する変数名の一覧を出力する
"""

verbose = 1

def listning(module):
    if verbose:
        print "-" * 30
        print "name:", module.__name__, "  file:", module.__file__
        print "-" * 30

    count = 0
    for attr in module.__dict__.keys():  # 名前空間の内容を調べる
        print "%02d) %s" % (count+1, attr),
        if attr[0:2] == "__":  # __で始まる属性はビルトイン
            print "<built-in name>"  # ビルトイン属性の出力
        else:
            print getattr(module, attr)  # .__dict__[attr]と同等
        count += 1

    if verbose:
        print "-" * 30
        print module.__name__, "has %d names" % count
        print "-" * 30

if __name__ == "__main__":
    import mydir
    listning(mydir)  # トップレベルファイルとして実行した場合、自身を引数とする

実行すると・・・

$ python mydir.py
------------------------------
name: mydir   file: /Users/ama-ch/python/mydir.py
------------------------------
01) listning <function listning at 0x6e770>
02) verbose 1
03) __builtins__ <built-in name>
04) __file__ <built-in name>
05) __name__ <built-in name>
06) __doc__ <built-in name>
------------------------------
mydir has 6 names
------------------------------

こんな感じで属性とその性質の一覧が出力できます。dir()を使うよりも見やすいですね。
同じmydirをdir()で見ると・・・

>>> import mydir
>>> dir(mydir)
['__builtins__', '__doc__', '__file__', '__name__', 'listning', 'verbose']

これだけだとよくわからないし、数が増えてくると読みにくくなります。


標準ライブラリもmydirで見てみよう。
・math

>>> import mydir
>>> import math
>>> mydir.listning(math)
------------------------------
name: math   file: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload/math.so
------------------------------
01) pow <built-in function pow>
02) cosh <built-in function cosh>
03) ldexp <built-in function ldexp>
04) hypot <built-in function hypot>
05) tan <built-in function tan>
06) asin <built-in function asin>
07) log <built-in function log>
08) fabs <built-in function fabs>
09) floor <built-in function floor>
10) sqrt <built-in function sqrt>
11) frexp <built-in function frexp>
12) degrees <built-in function degrees>
13) pi 3.14159265359
14) log10 <built-in function log10>
15) __doc__ <built-in name>
16) fmod <built-in function fmod>
17) atan <built-in function atan>
18) __file__ <built-in name>
19) ceil <built-in function ceil>
20) sinh <built-in function sinh>
21) __name__ <built-in name>
22) cos <built-in function cos>
23) e 2.71828182846
24) tanh <built-in function tanh>
25) radians <built-in function radians>
26) sin <built-in function sin>
27) atan2 <built-in function atan2>
28) modf <built-in function modf>
29) exp <built-in function exp>
30) acos <built-in function acos>
------------------------------
math has 30 names
------------------------------

piやeの値もわかります。


・sys

>>> import sys
>>> mydir.listning(sys)
------------------------------
name: sys   file:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/ama-ch/python/mydir.py", line 13, in listning
    print "name:", module.__name__, "  file:", module.__file__
AttributeError: 'module' object has no attribute '__file__'

ありゃ、ダメだ。どうやらsys.__file__というメンバがないらしい。
う〜ん、モジュールの実体がないってこと?でもインポートしてるんだからあるはず。

調べてみた

定義済みの (書き込み可能な) 属性: __name__ はモジュールの名前です; __doc__ は関数のドキュメンテーション文字列です。ドキュメンテーションがない場合は None になります; モジュールがファイルからロードされた場合、 __file__ はロードされたモジュールファイルのパス名です。インタプリタに静的にリンクされている C モジュールの場合、__file__ 属性はありません; 共有ライブラリから動的にロードされた拡張モジュールの場合、この属性は共有ライブラリファイルのパス名になります。

3.2 標準型の階層 - モジュール

Cで書かれたモジュールは__file__メンバがないという解釈でいいのかな?


そういえば

現在のところリロードが可能なのはPythonで書かれたモジュールのみであるという点です。Cで書かれたエクステンションモジュールなどは、リロードができないのです(インポートはPythonで書かれたモジュールと同じようにできる。)

「初めてのPython」 p.321

こんなことも書いてあったけど、これも関係してるんだろうか。でも初めてのPython結構情報が古いからなぁ。。。また調べる。