os.walkを便利に使える関数strollを書いた
リスト指定と正規表現マッチに対応し、ディレクトリパスとファイル名を返すようにして、関数名をnicewalkからstroll*1に変更(短い単語の方が良かった)
ディレクトリの扱いを明確化。rootはカレントディレクトリのディレクトリ名で、pathはカレントディレクトリのパス。ignorecaseを追加。
Python 3.5以上ではglobにrecursiveオプションが付いたため、"**"とrecursive=Trueを与えることで再帰的に辿ることができるようになった。そのため、以下はPython3.4以下が対象。
os.walk()はディレクトリを再帰的に辿りながら、ファイルを読み込んだり書き込む処理をする際に非常に便利だ。globだとディレクトリを再帰的に辿ることができず、ディレクトリ階層を意識しないといけない*2し、ディレクトリとファイルの違いをワイルドカードで示す必要があるので柔軟さに欠ける。またos.walk()では、取得したディレクトリやファイルのリストに対して、インプレースでの変更が可能になっているため、任意の条件で自由にソートやフィルタを行うことができる。そこで、各ディレクトリ・ファイルに対する条件を簡単に盛り込めるstroll
を書いた。
reduce
のこの使い方は好きで、リストをループでチェックするよりワンラインで書ける方が見やすくて良い。一度慣れてしまえば、それほど考えこまなくても流用できるので、いろんなところで多用している。リストが空の場合には、reduce
に与える初期値がそのまま判定結果になってしまうが、それが嫌ならリストを三項演算で判定して初期値を与えれば良い。
$ python --version Python 3.4.3 $ cat main.py from stroll import stroll import os print() print("=== ex1 (mtime) ===") for filepath in stroll("basedir",sortby=os.path.getmtime): print( filepath ) print() print("=== ex2 (mtime/reverse) ===") for filepath in stroll("basedir",sortby=os.path.getmtime,reverse=True): print( filepath ) print() print("=== ex3 (no_file) ===") for filepath in stroll("basedir",no_file=["1$","2$"],): print( filepath ) print() print("=== ex4 (yes_path) ===") for filepath in stroll("basedir",yes_path=["1$"],): print( filepath ) print() print("=== ex5 (no_root/len/reverse) ===") for filepath in stroll("basedir",no_root=["2$"],sortby=len,reverse=True): print( filepath ) print() print("=== ex6 (yes_file/yes_root) ===") for filepath in stroll("basedir",yes_file=["2$"],yes_root=["2$"]): print( file path )
$ find basedir basedir basedir/dir1 basedir/dir1/file11 basedir/dir1/file111 basedir/dir1/file1111 basedir/dir1/file12 basedir/dir1/file13 basedir/dir2 basedir/dir2/file21 basedir/dir2/file22 basedir/dir2/file222 basedir/dir2/file2222 basedir/dir2/file23 basedir/dir3 basedir/dir3/file31 basedir/dir3/file32 basedir/dir3/file33 basedir/dir3/file333 basedir/dir3/file3333 basedir/file0 $ ls -Rlrt --time-style=+"%m/%d_%H:%M:%S" basedir/ | awk '{print $5 " " $6 " " $7}' 0 02/09_21:24:50 file0 238 02/09_21:25:29 dir1 238 02/09_21:25:33 dir2 238 02/09_21:25:38 dir3 0 02/09_21:24:57 file11 0 02/09_21:24:58 file12 0 02/09_21:24:59 file13 0 02/09_21:25:28 file111 0 02/09_21:25:29 file1111 0 02/09_21:25:06 file22 0 02/09_21:25:06 file21 0 02/09_21:25:07 file23 0 02/09_21:25:32 file222 0 02/09_21:25:33 file2222 0 02/09_21:25:10 file31 0 02/09_21:25:11 file32 0 02/09_21:25:12 file33 0 02/09_21:25:37 file333 0 02/09_21:25:38 file3333 $ python main.py === ex1 (mtime) === basedir ('basedir', 'file0') basedir/dir1 ('basedir/dir1', 'file11') ('basedir/dir1', 'file12') ('basedir/dir1', 'file13') ('basedir/dir1', 'file111') ('basedir/dir1', 'file1111') basedir/dir2 ('basedir/dir2', 'file21') ('basedir/dir2', 'file22') ('basedir/dir2', 'file23') ('basedir/dir2', 'file222') ('basedir/dir2', 'file2222') basedir/dir3 ('basedir/dir3', 'file31') ('basedir/dir3', 'file32') ('basedir/dir3', 'file33') ('basedir/dir3', 'file333') ('basedir/dir3', 'file3333') === ex2 (mtime/reverse) === basedir ('basedir', 'file0') basedir/dir3 ('basedir/dir3', 'file3333') ('basedir/dir3', 'file333') ('basedir/dir3', 'file33') ('basedir/dir3', 'file32') ('basedir/dir3', 'file31') basedir/dir2 ('basedir/dir2', 'file2222') ('basedir/dir2', 'file222') ('basedir/dir2', 'file23') ('basedir/dir2', 'file21') ('basedir/dir2', 'file22') basedir/dir1 ('basedir/dir1', 'file1111') ('basedir/dir1', 'file111') ('basedir/dir1', 'file13') ('basedir/dir1', 'file12') ('basedir/dir1', 'file11') === ex3 (no_file) === basedir ('basedir', 'file0') basedir/dir1 ('basedir/dir1', 'file13') basedir/dir2 ('basedir/dir2', 'file23') basedir/dir3 ('basedir/dir3', 'file33') ('basedir/dir3', 'file333') ('basedir/dir3', 'file3333') === ex4 (yes_path) === basedir/dir1 ('basedir/dir1', 'file11') ('basedir/dir1', 'file111') ('basedir/dir1', 'file1111') ('basedir/dir1', 'file12') ('basedir/dir1', 'file13') === ex5 (no_root/len/reverse) === basedir ('basedir', 'file0') basedir/dir1 ('basedir/dir1', 'file1111') ('basedir/dir1', 'file111') ('basedir/dir1', 'file11') ('basedir/dir1', 'file12') ('basedir/dir1', 'file13') basedir/dir3 ('basedir/dir3', 'file3333') ('basedir/dir3', 'file333') ('basedir/dir3', 'file31') ('basedir/dir3', 'file32') ('basedir/dir3', 'file33') === ex6 (yes_file/yes_root) === basedir/dir2 ('basedir/dir2', 'file22') ('basedir/dir2', 'file222') ('basedir/dir2', 'file2222')