os.walk関数を使ってファイル数を列挙する

osモジュールの wolk 関数はちょっと面白い。ディレクトリを指定して呼び出すと、中に含まれるディレクトリ名、サブディレクトリのリスト、ファイルのリストを返すジェネレータを返してくれる。典型的にはこうやって使うみたい。

import os

for base_dir, dirs, files in os.walk("."):
    何らかの処理

そこで、ディレクトリに含まれるファイル数を列挙するスクリプトを書いてみた。

import os
import sys

for base_dir, dirs, files in os.walk(sys.argv[1]):
    num = len(files)
    print "%8d %-30s" % (num, base_dir)

実行結果:

^o^ > python count_files.py .
      83  .
       8  .\.git
      10  .\.git\hooks
       1  .\.git\info
       1  .\.git\logs
       0  .\.git\logs\refs
       1  .\.git\logs\refs\heads
       0  .\.git\logs\refs\remotes
       1  .\.git\logs\refs\remotes\origin
       1  .\.git\logs\refs\remotes\u
       0  .\.git\objects
       2  .\.git\objects\00
       1  .\.git\objects\01
       3  .\.git\objects\02
       3  .\.git\objects\03
       2  .\.git\objects\04
       1  .\.git\objects\07
       1  .\.git\objects\0c
       2  .\.git\objects\0d
       1  .\.git\objects\0e
       1  .\.git\objects\0f
       3  .\.git\objects\10
       1  .\.git\objects\13
       2  .\.git\objects\14
       3  .\.git\objects\16
       2  .\.git\objects\17
       1  .\.git\objects\19
       2  .\.git\objects\1a
       3  .\.git\objects\1b
       2  .\.git\objects\1c
       1  .\.git\objects\1f
       2  .\.git\objects\21
       5  .\.git\objects\22
       5  .\.git\objects\23
       1  .\.git\objects\25
       1  .\.git\objects\29
       2  .\.git\objects\2c
       1  .\.git\objects\2e
       2  .\.git\objects\2f
       2  .\.git\objects\30
       1  .\.git\objects\33
       1  .\.git\objects\35
       1  .\.git\objects\36
       1  .\.git\objects\37
       1  .\.git\objects\39
       3  .\.git\objects\3b
       1  .\.git\objects\3c
       2  .\.git\objects\40
       1  .\.git\objects\41
       1  .\.git\objects\42
       3  .\.git\objects\43
       1  .\.git\objects\44
       1  .\.git\objects\49
       4  .\.git\objects\4a
       2  .\.git\objects\4b
       2  .\.git\objects\4d
       1  .\.git\objects\4e
       3  .\.git\objects\4f
       1  .\.git\objects\51
       2  .\.git\objects\52
       2  .\.git\objects\53
       2  .\.git\objects\54
       1  .\.git\objects\55
       1  .\.git\objects\56
       3  .\.git\objects\57
       2  .\.git\objects\58
       1  .\.git\objects\59
       2  .\.git\objects\5a
       3  .\.git\objects\5d
       2  .\.git\objects\5e
       2  .\.git\objects\5f
       1  .\.git\objects\61
       1  .\.git\objects\62
       1  .\.git\objects\66
       1  .\.git\objects\67
       3  .\.git\objects\68
       1  .\.git\objects\69
       3  .\.git\objects\6a
       2  .\.git\objects\6b
       2  .\.git\objects\6c
       1  .\.git\objects\6d
       1  .\.git\objects\6f
       1  .\.git\objects\70
       1  .\.git\objects\71
       1  .\.git\objects\72
       1  .\.git\objects\75
       1  .\.git\objects\76
       1  .\.git\objects\77
       1  .\.git\objects\78
       1  .\.git\objects\79
       1  .\.git\objects\7b
       1  .\.git\objects\7c
       2  .\.git\objects\7d
       1  .\.git\objects\7f
       2  .\.git\objects\80
       1  .\.git\objects\85
       2  .\.git\objects\86
       1  .\.git\objects\87
       1  .\.git\objects\88
       1  .\.git\objects\89
       1  .\.git\objects\8b
       2  .\.git\objects\8d
       1  .\.git\objects\8e
       1  .\.git\objects\8f
       1  .\.git\objects\91
       2  .\.git\objects\93
       1  .\.git\objects\94
       3  .\.git\objects\95
       1  .\.git\objects\96
       3  .\.git\objects\97
       1  .\.git\objects\98
       2  .\.git\objects\9a
       3  .\.git\objects\9b
       1  .\.git\objects\9c
       3  .\.git\objects\a0
       2  .\.git\objects\a3
       1  .\.git\objects\a6
       1  .\.git\objects\a7
       1  .\.git\objects\a9
       1  .\.git\objects\ac
       1  .\.git\objects\ad
       1  .\.git\objects\ae
       1  .\.git\objects\b0
       2  .\.git\objects\b1
       1  .\.git\objects\b3
       3  .\.git\objects\b4
       2  .\.git\objects\b7
       1  .\.git\objects\b9
       3  .\.git\objects\ba
       1  .\.git\objects\bb
       1  .\.git\objects\bd
       1  .\.git\objects\c1
       1  .\.git\objects\c2
       1  .\.git\objects\c4
       2  .\.git\objects\c6
       2  .\.git\objects\c8
       1  .\.git\objects\c9
       2  .\.git\objects\cb
       1  .\.git\objects\cd
       2  .\.git\objects\ce
       3  .\.git\objects\cf
       2  .\.git\objects\d0
       1  .\.git\objects\d3
       4  .\.git\objects\d4
       1  .\.git\objects\d7
       3  .\.git\objects\d8
       2  .\.git\objects\d9
       2  .\.git\objects\da
       1  .\.git\objects\db
       3  .\.git\objects\dc
       5  .\.git\objects\dd
       1  .\.git\objects\e0
       1  .\.git\objects\e2
       1  .\.git\objects\e3
       1  .\.git\objects\e6
       1  .\.git\objects\e7
       2  .\.git\objects\e9
       1  .\.git\objects\ea
       1  .\.git\objects\ec
       5  .\.git\objects\ed
       3  .\.git\objects\ee
       1  .\.git\objects\ef
       1  .\.git\objects\f0
       1  .\.git\objects\f1
       2  .\.git\objects\f2
       1  .\.git\objects\f3
       1  .\.git\objects\f4
       2  .\.git\objects\f5
       1  .\.git\objects\f8
       1  .\.git\objects\fc
       1  .\.git\objects\fd
       1  .\.git\objects\fe
       0  .\.git\objects\info
       0  .\.git\objects\pack
       0  .\.git\refs
       1  .\.git\refs\heads
       0  .\.git\refs\remotes
       1  .\.git\refs\remotes\origin
       1  .\.git\refs\remotes\u
       0  .\.git\refs\tags
      10  .\projecteuler

git のリポジトリのファイルが多いな。

urllibモジュールの超簡単なサンプル(その3)

RSSフィードを取得して記事のタイトルを表示する。

import sys
import re
import urllib

url = sys.argv[1]

src = urllib.urlopen(url).read()

for title in re.findall(r"", src):
    print title.decode("utf-8")

実行例:

^o^ > python get_feed.py https://blog.panicblanket.com/feed
blog.PanicBlanket.com
urllibモジュールの超簡単なサンプル(その2)
urllibモジュールの超簡単なサンプル
変数に関数と同じ名前をつけてはいけない
== 演算子と is 演算子
randomモジュール
fileinputモジュール
Rubyで点数を集計するとき、あなたはどうしてますか? をPythonで
Pythonで偽と見なされる値
エラトステネスの篩
ファイルの文字数、ワード数、行数を数える

タイトルの抜き出しを正規表現でやってるので、ブログのタイトルまで表示されてるけど、とりあえずはこんなものだろう。ちゃんとやるならXML解析をやるべきだろうな。

urllibモジュールの超簡単なサンプル(その2)

URL を指定してヘッダーを得る。

import urllib
import sys

url = sys.argv[1]

r = urllib.urlopen(url)
info = r.info()

for key in info.keys():
    print key, ":", info[key]

実行結果:

^o^ > python httphead.py https://blog.panicblanket.com/
date : Sun, 03 Feb 2013 00:12:51 GMT
connection : close
content-type : text/html; charset=UTF-8
x-pingback : https://blog.panicblanket.com/xmlrpc.php
server : Apache/2.2.23

urllibモジュールの超簡単なサンプル

コマンドラインから入力された url を data.html に保存する。

import urllib
import sys

url = sys.argv[1]

filename = "data.html"

urllib.urlretrieve(url, filename)

実行結果の data.html(の冒頭部分)

<!DOCTYPE html>
<!--[if IE 6]>
<html id="ie6" lang="ja">
<![endif]-->
<!--[if IE 7]>
<html id="ie7" lang="ja">
<![endif]-->
<!--[if IE 8]>
<html id="ie8" lang="ja">
<![endif]-->
<!--[if !(IE 6) | !(IE 7) | !(IE 8)  ]><!-->
<html lang="ja">
<!--<![endif]-->
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>変数に関数と同じ名前をつけてはいけない | blog.PanicBlanket.com</title>
<link rel="profile" href="http://gmpg.org/xfn/11" />
<link rel="stylesheet" type="text/css" media="all" href="https://blog.panicblanket.com/wp-content/themes/twentyeleven/style.css" />
<link rel="pingback" href="https://blog.panicblanket.com/xmlrpc.php" />
<!--[if lt IE 9]>
<script src="https://blog.panicblanket.com/wp-content/themes/twentyeleven/js/html5.js" type="text/javascript"></script>
<![endif]-->
<link rel="alternate" type="application/rss+xml" title="blog.PanicBlanket.com » フィード" href="https://blog.panicblanket.com/feed" />
<link rel="alternate" type="application/rss+xml" title="blog.PanicBlanket.com » コメントフィード" href="https://blog.panicblanket.com/comments/feed" />
<link rel="alternate" type="application/rss+xml" title="blog.PanicBlanket.com » 変数に関数と同じ名前をつけてはいけない のコメントのフィード" href="https://blog.panicblanket.com/archives/605/feed" />
<link rel='stylesheet' id='crayon_style-css'  href='https://blog.panicblanket.com/wp-content/plugins/crayon-syntax-highlighter/css/crayon_style.css?ver=2.1.1' type='text/css' media='all' />
<link rel='stylesheet' id='crayon_global_style-css'  href='https://blog.panicblanket.com/wp-content/plugins/crayon-syntax-highlighter/css/global_style.css?ver=2.1.1' type='text/css' media='all' />
<link rel='stylesheet' id='crayon-theme-classic-css'  href='https://blog.panicblanket.com/wp-content/plugins/crayon-syntax-highlighter/themes/classic/classic.css?ver=2.1.1' type='text/css' media='all' />
<link rel='stylesheet' id='crayon-font-monaco-css'  href='https://blog.panicblanket.com/wp-content/plugins/crayon-syntax-highlighter/fonts/monaco.css?ver=2.1.1' type='text/css' media='all' />
<link rel='stylesheet' id='wp-syntax-css-css'  href='https://blog.panicblanket.com/wp-content/plugins/wp-syntax/wp-syntax.css?ver=3.5.1' type='text/css' media='all' />
<link rel='stylesheet' id='thickbox-css'  href='https://blog.panicblanket.com/wp-includes/js/thickbox/thickbox.css?ver=20121105' type='text/css' media='all' />
<link rel='stylesheet' id='amazonjs-css'  href='https://blog.panicblanket.com/wp-content/plugins/amazonjs/amazonjs.css?ver=0.1beta3c' type='text/css' media='all' />
<script type='text/javascript' src='https://blog.panicblanket.com/wp-includes/js/jquery/jquery.js?ver=1.8.3'></script>
<script type='text/javascript'>
/* <![CDATA[ */
var CrayonSyntaxSettings = {"version":"2.1.1","is_admin":"0","ajaxurl":"https:\/\/blog.panicblanket.com\/wp-admin\/admin-ajax.php","prefix":"crayon-","setting":"crayon-setting","selected":"crayon-setting-selected","changed":"crayon-setting-changed","special":"crayon-setting-special","orig_value":"data-orig-value","debug":""};
var CrayonSyntaxStrings = {"copy":"\u8cbc\u308a\u4ed8\u3051\u306b\u30b3\u30d4\u30fc\u3001%s\u306b%s\u3092\u62bc\u3057\u3066\u3001","minimize":"Click To Expand Code"};
/* ]]> */
</script>
<script type='text/javascript' src='https://blog.panicblanket.com/wp-content/plugins/crayon-syntax-highlighter/js/util.js?ver=2.1.1'></script>
<script type='text/javascript' src='https://blog.panicblanket.com/wp-content/plugins/crayon-syntax-highlighter/js/crayon.js?ver=2.1.1'></script>
<script type='text/javascript' src='https://blog.panicblanket.com/wp-includes/js/comment-reply.min.js?ver=3.5.1'></script>
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://blog.panicblanket.com/xmlrpc.php?rsd" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://blog.panicblanket.com/wp-includes/wlwmanifest.xml" /> 
<link rel='prev' title='== 演算子と is 演算子' href='https://blog.panicblanket.com/archives/600' />
<meta name="generator" content="WordPress 3.5.1" />
<link rel='canonical' href='https://blog.panicblanket.com/archives/605' />
<link rel='shortlink' href='https://blog.panicblanket.com/?p=605' />
	<style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
<style type="text/css" id="custom-background-css">
body.custom-background { background-color: #e2e2e2; }
</style>
</head>

変数に関数と同じ名前をつけてはいけない

Project Eulerのある問題を解いてるときにはまったのでメモ。
整数と文字列からスコアを計算してその合計を求める問題なんだけど、途中でこういうコードを書いた。

def name_score(num, str):
    v = sum(map((lambda c: ord(c) - 64), str))
    return num * v

print name_score(1, "FOO")

names = ["ANDY", "BILL", "CHARLIE"]

n = 0
sum = 0
for name in names:
    n += 1
    score = name_score(n, name)
    sum += score

print sum

name_score がスコアを計算する関数で、6行目と16行目(forブロックの中)の2箇所で呼び出している(6行目はちゃんと動くかの確認用)。ところが、これを実行するとこうなる。

^o^ > python a.py
36
Traceback (most recent call last):
  File "a.py", line 16, in 
    score = name_score(n, name)
  File "a.py", line 2, in name_score
    v = sum(map((lambda c: ord(c) - 64), str))
TypeError: 'int' object is not callable

1回目の呼び出し(6行目)ではちゃんとスコアが計算されているのに、2回目(forブロックの中)ではエラーになって、’int’オブジェクトは callable じゃないと怒られる。
これで小一時間ほども悩んだけど、問題は13行目のsumという変数と2行目で使っているsum関数の名前が同じことだった。

Pythonでは、定義した関数をほかの変数に代入することができる。

>>> def hello(name):
...     print "Hello,", name
...
>>> hello("Andy")
Hello, Andy
>>> greeting = hello
>>> greeting("Bill")
Hello, Bill

それはいいんだけど、逆に関数名にほかの値、たとえば整数を代入することもできてしまう。

>>> hello = 1
>>> hello("Charlie")
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'int' object is not callable

hello には 1 を代入してしまったので、関数呼び出しのつもりがエラーになってしまっている。上で紹介したコードでも13行目で sum に 0 を代入しているので、同じことが起こったわけだ。
結局、変数名を変えたら期待通りに動いてくれた。

def name_score(num, str):
    v = sum(map((lambda c: ord(c) - 64), str))
    return num * v

print name_score(1, "FOO")

names = ["ANDY", "BILL", "CHARLIE"]

n = 0
sum_of_score = 0
for name in names:
    n += 1
    score = name_score(n, name)
    sum_of_score += score

print sum_of_score
^o^ > python b.py
36
282

Python では関数もオブジェクトだからかもしれないけど、普通の変数名と関数名の間に区別がないようだ。

今日の結論:変数に関数と同じ名前をつけてはいけない。