Pythonクックブック(3章)
dateutilモジュールの続き
rrule
繰り返し処理を簡単に出来る。
>>> from dateutil.rrule import * >>> from datetime import * >>> import calendar >>> today=datetime.today() >>> firstday=today.replace(day=1) >>> lastday = today.replace(day=calendar.monthrange(today.year, today.month)[1]) >>> # 今月の火曜日、木曜日をリストアップ >>> list(rrule(DAILY, byweekday=(TU, TH), dtstart=firstday, until=lastday)) [datetime.datetime(2011, 7, 5, 22, 17, 2), datetime.datetime(2011, 7, 7, 22, 17, 2), datetime.datetime(2011, 7, 12, 22, 17, 2), datetime.datetime(2011, 7, 14, 22, 17, 2), datetime.datetime(2011, 7, 19, 22, 17, 2), datetime.datetime(2011, 7, 21, 22, 17, 2), datetime.datetime(2011, 7, 26, 22, 17, 2), datetime.datetime(2011, 7, 28, 22, 17, 2)] >>> # 今月の偶数週の水曜日をリストアップ >>> list(rrule(WEEKLY, interval=2, byweekday=(WE), dtstart=firstday, until=lastday)) [datetime.datetime(2011, 7, 13, 22, 17, 2), datetime.datetime(2011, 7, 27, 22, 17, 2)] >>> list(rrule(DAILY, interval=2, byweekday=(WE), dtstart=firstday, until=lastday)) [datetime.datetime(2011, 7, 13, 22, 17, 2), datetime.datetime(2011, 7, 27, 22, 17, 2)] >>> # 今年の残りの月の第一水曜日をリストアップ >>> list(rrule(MONTHLY, byweekday=WE(1), dtstart=firstday, until=datetime(2011, 12, 31))) [datetime.datetime(2011, 7, 6, 22, 17, 2), datetime.datetime(2011, 8, 3, 22, 17, 2), datetime.datetime(2011, 9, 7, 22, 17, 2), datetime.datetime(2011, 10, 5, 22, 17, 2), datetime.datetime(2011, 11, 2, 22, 17, 2), datetime.datetime(2011, 12, 7, 22, 17, 2)] >>>
DAILYでもWEEKLYでも同じような結果になる。どっちを使うべきなんだろうか。。。
出勤日数の計算
[kobakoba0723@fedora13-intel64 ~]$ cat count_dayoff.py from dateutil import rrule import datetime def workdays(start, end, holidays=0, days_off=None): if days_off == None: days_off = (5, 6) workdays = [x for x in range(7) if x not in days_off] days = rrule.rrule(rrule.DAILY, dtstart=start, until=end, byweekday=workdays) return days.count() - holidays if __name__ == '__main__': testdates = [(datetime.date(2011, 7, 1), datetime.date(2011, 8, 31), 3), (datetime.date(2011, 9, 1), datetime.date(2011, 11, 30), 3) ] def test(testdates, days_off=None): for s, e, h in testdates: print '\ttotal workdays from %s to %s are %s with %s holidays' % ( s, e, workdays(s, e, h, days_off), h) print 'Saturday & Sunday are day off.' test(testdates) print 'Sunday is day off.' test(testdates, days_off=[6]) [kobakoba0723@fedora13-intel64 ~]$ python count_dayoff.py Saturday & Sunday are day off. total workdays from 2011-07-01 to 2011-08-31 are 41 with 3 holidays total workdays from 2011-09-01 to 2011-11-30 are 62 with 3 holidays Sunday is day off. total workdays from 2011-07-01 to 2011-08-31 are 50 with 3 holidays total workdays from 2011-09-01 to 2011-11-30 are 75 with 3 holidays [kobakoba0723@fedora13-intel64 ~]$
参考サイト
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る
Pythonクックブック(3章)
dateutilモジュール。
インストール
サードパーティのモジュールなのでまずはインストールから。
サイトからtarballを持ってくるやり方もあるみたいだけど、easy_installでインストール可能なので、
[kobakoba0723@fedora13-intel64 ~]$ easy_install python-dateutil Searching for python-dateutil Reading http://pypi.python.org/simple/python-dateutil/ Reading http://labix.org/python-dateutil Best match: python-dateutil 2.0 Downloading http://labix.org/download/python-dateutil/python-dateutil-2.0.tar.gz Processing python-dateutil-2.0.tar.gz Running python-dateutil-2.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-sXQGAy/python-dateutil-2.0/egg-dist-tmp-rPlpIE Adding python-dateutil 2.0 to easy-install.pth file Installed /home/kobakoba0723/lib/python2.6/site-packages/python_dateutil-2.0-py2.6.egg Processing dependencies for python-dateutil Finished processing dependencies for python-dateutil [kobakoba0723@fedora13-intel64 ~]$
あれ、2.0が入っちゃった。。。
公開サイトを見ると、2.x系は1.5みたいなんだけどなぁ。まぁ、いいか。
relativedelta, rruleモジュール
dateutil.relativedelta は datetime.timedelta のような差分を扱うモジュール
>>> import dateutil >>> import datetime >>> now = datetime.datetime.now() >>> now datetime.datetime(2011, 7, 4, 22, 26, 22, 723727) >>> now + dateutil.relativedelta.relativedelta(months=+1) datetime.datetime(2011, 8, 4, 22, 26, 22, 723727) >>> now + dateutil.relativedelta.relativedelta(months=+1, weeks=+1) datetime.datetime(2011, 8, 11, 22, 26, 22, 723727) >>> >>> today = datetime.date.today() >>> today datetime.date(2011, 7, 4) >>> today + dateutil.relativedelta.relativedelta(months=+1, weeks=+1) datetime.date(2011, 8, 11) >>> today + dateutil.relativedelta.relativedelta(months=+2, weeks=+1, hour=10) datetime.datetime(2011, 9, 11, 10, 0) >>>
relativedeltaを使うと、うるう年をモジュール側でちゃんと考慮して計算してくれる。
>>> datetime.date(2008, 1, 31) + dateutil.relativedelta.relativedelta(months=+1) datetime.date(2008, 2, 29) >>> datetime.date(2011, 1, 31) + dateutil.relativedelta.relativedelta(months=+1) datetime.date(2011, 2, 28) >>> >>> datetime.date(2000, 2, 29) datetime.date(2000, 2, 29) >>> datetime.date(2000, 2, 29) + dateutil.relativedelta.relativedelta(years=+1) datetime.date(2001, 2, 28) >>> datetime.date(2000, 2, 29) + dateutil.relativedelta.relativedelta(years=-1) datetime.date(1999, 2, 28) >>> >>> datetime.date(2000, 1, 1) + dateutil.relativedelta.relativedelta(nlyearday=60) datetime.date(2000, 3, 1) >>> datetime.date(2000, 1, 1) + dateutil.relativedelta.relativedelta(yearday=60) datetime.date(2000, 2, 29) >>>
つぎにrruleモジュールと思ってhelpでも眺めようと思ったらエラーが。。。
>>> help(dateutil.rrule) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'rrule' >>> from dateutil import rrule Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/kobakoba0723/lib/python2.6/site-packages/python_dateutil-2.0-py2.6.egg/dateutil/rrule.py", line 13, in <module> import _thread ImportError: No module named _thread >>>
どうも_threadっていうモジュールがないからインポート処理が進まない。
調べてみると_threadは python 3 のモジュールだから進まない。python 2.x では thread って名前だった。
やっぱり、python-dateutil-2.0だったからうまくいかないのか。
アンインストール&&再インストール
easy_installで入れたんだから、easy_installで削除出来るといいなと思ってググってると、
"-mxN"オプション + モジュール削除でアンインストールできる。
[kobakoba0723@fedora13-intel64 site-packages]$ easy_install -mxN python_dateutilSearching for python-dateutil Best match: python-dateutil 2.0 Processing python_dateutil-2.0-py2.6.egg Using /home/kobakoba0723/lib/python2.6/site-packages/python_dateutil-2.0-py2.6.egg Because this distribution was installed --multi-version, before you can import modules from this package in an application, you will need to 'import pkg_resources' and then use a 'require()' call similar to one of these examples, in order to select the desired version: pkg_resources.require("python-dateutil") # latest installed version pkg_resources.require("python-dateutil==2.0") # this exact version pkg_resources.require("python-dateutil>=2.0") # this version or higher [kobakoba0723@fedora13-intel64 site-packages]$ rm -rf python_dateutil-2.0-py2.6.egg/ [kobakoba0723@fedora13-intel64 site-packages]$ python Python 2.6.4 (r264:75706, Apr 1 2010, 02:55:51) [GCC 4.4.3 20100226 (Red Hat 4.4.3-8)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import dateutil Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named dateutil >>>
ちゃんとアンインストールできたようなので、次は1.5をインストールする。
easy_installで版数を指定する場合、"パッケージ名 == 版数"とやれば版数指定インストールが出来る。
[kobakoba0723@fedora13-intel64 python-dateutil-1.5]$ easy_install "python-dateutil == 1.5" Searching for python-dateutil==1.5 Reading http://pypi.python.org/simple/python-dateutil/ Reading http://labix.org/python-dateutil Best match: python-dateutil 1.5 Downloading http://labix.org/download/python-dateutil/python-dateutil-1.5.tar.gz Processing python-dateutil-1.5.tar.gz Running python-dateutil-1.5/setup.py -q bdist_egg --dist-dir /tmp/easy_install-WjExNi/python-dateutil-1.5/egg-dist-tmp-DH9yWO Adding python-dateutil 1.5 to easy-install.pth file Installed /home/kobakoba0723/lib/python2.6/site-packages/python_dateutil-1.5-py2.6.egg Processing dependencies for python-dateutil==1.5 Finished processing dependencies for python-dateutil==1.5 [kobakoba0723@fedora13-intel64 python-dateutil-1.5]$
さて、今度はrruleのヘルプが見れるといいな。
>>> import dateutil >>> help(dateutil.rrule) >>> dateutil.rrule.rrule(dateutil.rrule.MONTHLY, dtstart=datetime.datetime(2011, 07, 04)) <dateutil.rrule.rrule instance at 0x1896e18> >>>
よし、見れたし、なんかうまく動きそう。続きは明日やろう。
参考サイト
python dateutil@Labix
The Python Standard Library@Python v3.1.3 documentation
Python標準ライブラリ@Python 2.6.2 documentation
pythonモジュールのアンインストール@kokiyaの日記
setuptoolsでモジュールのバージョンを指定する方法@DSAS開発者の部屋
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る
Pythonクックブック(3章)
日付の続き、今日はdatetimeモジュール*1。明日はdateutilモジュールを使ってみる。
datetimeモジュール
基本的な日付型および時間型を扱うためのモジュール。
次の5つのクラスが属している
datetime |- class timedelta : time/date/datetimeクラスの2つのインスタンスの差分を表す |- class tzinfo : タイムゾーン情報の抽象基底クラス(必ず派生クラスを作成して使う) |- class time : ローカルの時間(時,分,秒,マイクロ秒,タイムゾーン)を表す |- class date : 日付(年,月,日)を表す |- class datetime : dateクラスとtimeクラスの全情報を表す
昨日、今日、明日
>>> import datetime >>> today = datetime.date.today() >>> yesterday = today - datetime.timedelta(days=1) >>> tomorrow = today + datetime.timedelta(days=1) >>> yesterday, today, tomorrow (datetime.date(2011, 6, 27), datetime.date(2011, 6, 28), datetime.date(2011, 6, 29)) >>> print yesterday, today, tomorrow 2011-06-27 2011-06-28 2011-06-29 >>>
1日前、現時点、1日後
>>> now = datetime.datetime.now() >>> one_day_before = now - datetime.timedelta(days=1) >>> one_day_after = now + datetime.timedelta(days=1) >>> one_day_before, now, one_day_after (datetime.datetime(2011, 6, 27, 0, 20, 17, 854036), datetime.datetime(2011, 6, 28, 0, 20, 17, 854036), datetime.datetime(2011, 6, 29, 0, 20, 17, 854036)) >>> print one_day_before, now, one_day_after 2011-06-27 00:20:17.854036 2011-06-28 00:20:17.854036 2011-06-29 00:20:17.854036 >>>
月始め、今日、月末
月毎の最終日は、calendar.monthrange(year, month) -> [月始めの曜日、月末の日にち] から。
>>> import calendar >>> import datetime >>> today = datetime.date.today() >>> calendar.monthrange(today.year, today.month) (2, 30) >>> first_day = today.replace(day=1) >>> last_day = today.replace(day=calendar.monthrange(today.year, today.month)[1]) >>> first_day, today, last_day (datetime.date(2011, 6, 1), datetime.date(2011, 6, 28), datetime.date(2011, 6, 30)) >>> print first_day, today, last_day 2011-06-01 2011-06-28 2011-06-30 >>>
その他
組込み関数sumの第一引数には、ジェネレータを指定することが出来る。
大量のデータを扱う場合は、メモリの節約になる(はず)
[kobakoba0723@fedora13-intel64 ~]$ cat sumgenerator.py print sum((x * x for x in range(10))) [kobakoba0723@fedora13-intel64 ~]$ python -m pdb sumgenerator.py > /home/kobakoba0723/sumgenerator.py(1)<module>() -> print sum((x*x for x in range(10))) (Pdb) s --Call-- > /home/kobakoba0723/sumgenerator.py(1)<genexpr>() -> print sum((x*x for x in range(10))) (Pdb) > /home/kobakoba0723/sumgenerator.py(1)<genexpr>() -> print sum((x*x for x in range(10))) (Pdb) --Return-- > /home/kobakoba0723/sumgenerator.py(1)<genexpr>()->0 -> print sum((x*x for x in range(10))) (Pdb) --Call-- > /home/kobakoba0723/sumgenerator.py(1)<genexpr>()->0 -> print sum((x*x for x in range(10))) (Pdb) > /home/kobakoba0723/sumgenerator.py(1)<genexpr>()->0 -> print sum((x*x for x in range(10))) (Pdb)
参考サイト
モジュールインデックス@Python 2.6.2 document
標準ライブラリ@Python 2.6.2 document
Pythonでの日付関連処理@Groove Labo
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る
*1:ところどころでcalendarモジュールも使ってる
Pythonクックブック(3章)
昨日のめざせ会社の星を観てたら、「25分作業して5分休憩する」ってことをやってる人が出てた。
調べてみると、この方法「ポモドーロ・テクニック」って呼ばれてる時間管理術。
「○ポモドーロ」って見かけたり、翻訳本「アジャイルな時間管理術 ポモドーロテクニック入門」が出たりしてた。
「ポモドーロって何?」って気になったけど、その時は調べてなかったなぁ。
興味をもったらその時に調べる癖をつけんと、数日も経つと忘れてしまって、いつまで経っても解らんままだ。
timeモジュール
時刻データにアクセスするためのモジュール。
時刻の考え方は、UTCという世界標準時があり、そこからの時差を加味したローカル時間(日本ならJST)で表現される。
コンピュータでの時刻の管理方法は、時刻データをエポックと呼ばれる任意の時刻からの経過秒数で行っている。
エポックの値はプラットフォームに依存するが、通常1970年1月1日午前0時となっている
Pythonプログラムからは、time.gmtime(0)の値を見ればエポックがいつなのかがわかる。
>>> import time >>> time.gmtime(0) time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0) >>> time.gmtime(0).tm_year 1970
time.gmtime()は以下の整数値からなるstruct_time(シーケンス)を返してくれる。
Index | Attribute | Value |
---|---|---|
0 | tm_year | 年[4桁] |
1 | tm_mon | 月[1〜12] |
2 | tm_mday | 日[1〜31] |
3 | tm_hour | 時[0〜23] |
4 | tm_min | 分[0〜59] |
5 | tm_sec | 秒[0〜61]*1 |
6 | tm_wday | 曜日[0〜6]*2 |
7 | tm_yday | 1年の何日目か[0〜366] |
8 | tm_isdst | サマータイムが有効(1)か否(0)か*3 |
コンピュータはepochからの経過秒数で時刻データを扱うが、
Pythonプログラムでの時刻データの扱い方は2種類ある。
- epochからの経過秒数として扱う
- struct_timeシーケンスとして扱う
Pythonプログラムで時刻を表示方法は以下の2種類ある。
- プログラムの内部データをそのまま表示する
- 人間に解りやすく加工して表示する
内部データをそのまま表示する。
出力をUTC/ローカル時間どちらで表示するのか、入出力の扱いをどうするのかで使う関数が異なる。
method | 表示時刻 | input | output | in/out反転 |
---|---|---|---|---|
time.gmtime | UTC | epochからの秒数 | struct_timeシーケンス | calendar.timegm |
time.localtime | ローカル時間 | epochからの秒数 | struct_timeシーケンス | time.mktime |
time.strptime | − | 文字列(,文字列形式) | struct_timeシーケンス | ??? |
人間に解りやすくして表示する。
出力の形式が固定*4/自由どちらで表示するのか、入力をどうするのかで使う関数が異なる。
method | input | 出力形式 | 表示時刻 |
---|---|---|---|
time.asctime | struct_timeシーケンス | 固定 | 入力と同じ |
time.ctime | epochからの秒数 | 固定 | ローカル時間 |
time.strftime | struct_timeシーケンス | 自由 | 入力と同じ |
エポック以前は扱えないって書いてあるけど、2000年問題の所に1969とか書いてあるし、
実はエポック以前もいけるんじゃないかと思って試してみたけど、
epochからstruct_timeへの変換は"○"、struct_timeからepochへの変換は"×"って結果になった。
>>> time.localtime(-10**10) time.struct_time(tm_year=1653, tm_mon=2, tm_mday=10, tm_hour=15, tm_min=32, tm_sec=19, tm_wday=0, tm_yday=41, tm_isdst=0) >>> time.mktime(time.localtime(-10**10)) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: year out of range >>>
色々試してみたら、tm_year=1900以降ならば動きはするらしい。まぁ、正しく動く保証は当然ないんだろうけど。
>>> time.mktime((1899,0,0,0,0,0,0,0,0)) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: year out of range >>> time.mktime((1900,0,0,0,0,0,0,0,0)) -2211786000.0 >>>
参考サイト
モジュールインデックス@Python 2.6.2 document
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る
Pythonクックブック(2章)
ファイル操作の続き
特定ディレクトリの探索(glob)
globモジュールは、Unix 形式のパス名のパターン展開をしてくれるので、
下位ディレクトリを調べる必要がないような探索にはos.walk/fnmatchを使わなくてもよい。
globモジュール自体が、os.listdir()/fnmatch.fnmatch()を使っているからなのか。
[kobakoba0723@fedora13-intel64 ~]$ cat findgrepglob.py import os import glob def find_grep(search_dir, pattern='*'): for match in glob.glob(os.path.join(search_dir, pattern)): yield match # for search_dir in search_dirs.split(os.pathsep): # for pattern in patterns.split(';'): # for match in glob.glob(os.path.join(search_dir, pattern)): # yield match if __name__ == '__main__': import sys if len(sys.argv) != 3: print 'Usage: python %s <search_dirs> <patterns>' % (sys.argv[0], ) for search_dir in sys.argv[1].split(os.pathsep): for pattern in sys.argv[2].split(';'): for file in find_grep(search_dir, pattern): print file [kobakoba0723@fedora13-intel64 ~]$ python findgrepglob.py "$(echo $PATH)" '*.sh' /usr/bin/gnome-power-bugreport.sh /usr/bin/pm-utils-bugreport-info.sh /usr/bin/amuFormat.sh /usr/bin/pv.sh /usr/bin/lprsetup.sh /usr/bin/lesspipe.sh /usr/bin/setup-nsssysinit.sh /usr/bin/packagekit-bugreport.sh /usr/bin/unix-lpr.sh [kobakoba0723@fedora13-intel64 ~]$
findの検索対象に複数ディレクトリ指定できるってのがわかって嬉しかった。
nameオプションに複数のパターンを渡すことって出来ないんだろうか。
[kobakoba0723@fedora13-intel64 ~]$ find $(echo $PATH | sed 's/:/ /g') -type f -name "*.sh" /usr/bin/gnome-power-bugreport.sh /usr/bin/pm-utils-bugreport-info.sh /usr/bin/amuFormat.sh /usr/bin/pv.sh /usr/bin/lprsetup.sh /usr/bin/lesspipe.sh /usr/bin/setup-nsssysinit.sh /usr/bin/packagekit-bugreport.sh /usr/bin/unix-lpr.sh [kobakoba0723@fedora13-intel64 ~]$
2日前、Usageメッセージのモジュール名ハードコーディングしてるし。。。恥ずかし。
それと、which 相当のことをやる時に、$PATHの内容をソースにハードコーディングしてたけど、
osモジュールのenvironっていうディクショナリに'PATH'でアクセス(os.environ['PATH'])すれば良かったんだ。
その他(itertools)
itertoolsはイテレータを生成するモジュール。
itertools.zip()はイテレータブルオブジェクトを受け取って、リストのイテレータを返す。
>>> import itertools >>> for elements in itertools.izip(['a', 'b', 'c', 'd'], ['a', 'b', 'e', 'd']): ... print elements ... ('a', 'a') ('b', 'b') ('c', 'e') ('d', 'd') >>> for elements in itertools.izip_longest('spam', 'egg', 'snake'): ... print elements ... ('s', 'e', 's') ('p', 'g', 'n') ('a', 'g', 'a') ('m', None, 'k') (None, None, 'e') >>>
その他(python以外)
昨日は、初めてソースにパッチを当てたり、srpmからrpmを作ったりしてみた。
LPIの試験でコマンドの使い方は知ってるつもりだったけど、いざやってみると出来ないもんだ。
実機上で始めて動いたら何ともいえず嬉しかった、しょうもないことしかやってないけど。
参考サイト
モジュールインデックス@Python 2.6.2 document
RPMバージョン4.8の機能と変更点@HDE コラム
ニュースレター20号@レッドハット
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る
Pythonクックブック(2章)
ファイル操作の続き
ディレクトリの探索(os.walk, fnmatch)
os.walk(top)を実行すると、(dirpath, subdirnames, filenames) を返す。
[kobakoba0723@fedora13-intel64 ~]$ ls -R top/ top/: eggs.txt spam.txt sub top/sub: hoge.data piyo.data >>> import os >>> for (dirpath, subdirs, files) in os.walk('top'): ... print dirpath ... print files, subdirs ... top ['spam.txt', 'eggs.txt'] ['sub'] top/sub ['piyo.data', 'hoge.data'] [] >>>
fnmatchは シェルのワイルドカードを使ったファイル名のマッチングをするモジュール。
fnmatch.fnmatch(name, pattern)はファイル名nameが パターンpattern にマッチした場合 True を返す
この2つを組み合わせると find | grep と同じようなことが出来る。
[kobakoba0723@fedora13-intel64 ~]$ find top/ | grep -e '.*\.txt' -e '.*\.data' top/spam.txt top/eggs.txt top/sub/piyo.data top/sub/hoge.data [kobakoba0723@fedora13-intel64 ~]$
fnmatchはシェルのワイルドカードを解釈し、grepは正規表現を解釈するので実行時の引数が違う。
[kobakoba0723@fedora13-intel64 ~]$ cat findgrep.py import os import fnmatch def find_grep(root, patterns='*'): patterns = patterns.split(';') for (dirpath, subdirs, files) in os.walk(root): files.sort() for name in files: for pattern in patterns: if fnmatch.fnmatch(name, pattern): yield os.path.join(dirpath, name) break if __name__ == '__main__': import sys if len(sys.argv) != 3: print 'Usage: python findgrep.py <top> <pattern>' sys.exit(1) for filename in find_grep(sys.argv[1], sys.argv[2]): print filename [kobakoba0723@fedora13-intel64 ~]$ python findgrep.py 'top' '*.txt;*.data' top/eggs.txt top/spam.txt top/sub/hoge.data top/sub/piyo.data [kobakoba0723@fedora13-intel64 ~]$
拡張子の変更(os.walk, os.rename)
os.rename(src, dst) は mv src dst と同じ。
os.walk と os.rename を組み合わせると、シェルの forループ + mv と同じことが出来る。
[kobakoba0723@fedora13-intel64 ~]$ ls -R top.shell/ top.shell/: eggs.txt spam.txt sub top.shell/sub: hoge.data piyo.data [kobakoba0723@fedora13-intel64 ~]$ for file in $(find top.shell/ -type f | grep .*\.txt) > do > mv $file ${file%%.txt}.data > done [kobakoba0723@fedora13-intel64 ~]$ ls -R top.shell/ top.shell/: eggs.data spam.data sub top.shell/sub: hoge.data piyo.data [kobakoba0723@fedora13-intel64 ~]$
[kobakoba0723@fedora13-intel64 ~]$ cat swapextension.py import os def swap_extension(dir, before, after): if before[:1] != '.': before = '.' + before extension_len = -len(before) if after[:1] != '.': after = '.' + after for (dirpath, subdirs, files) in os.walk(dir): for filename in files: old_filepath = os.path.join(dirpath, filename) new_filepath = old_filepath[:extension_len] + after os.rename(old_filepath, new_filepath) if __name__ == '__main__': import sys if len(sys.argv) != 4: print "Usage: python swapextension.py <rootdir> <before> <after>" sys.exit(1) swap_extension(sys.argv[1], sys.argv[2], sys.argv[3]) [kobakoba0723@fedora13-intel64 ~]$ ls -R top.py/ top.py/: eggs.txt spam.txt sub top.py/sub: hoge.data piyo.data [kobakoba0723@fedora13-intel64 ~]$ python swapextension.py top.py '.txt' '.data' [kobakoba0723@fedora13-intel64 ~]$ ls -R top.py/ top.py/: eggs.data spam.data sub top.py/sub: hoge..data piyo..data [kobakoba0723@fedora13-intel64 ~]$
サーチパスからファイルを探す(os.path)
os.path モジュールはプラットフォームに依存しない共通のパス名操作モジュール
このモジュールを使うと、which コマンドと同じようなことが出来る。
[kobakoba0723@fedora13-intel64 ~]$ which pep8 ~/bin/pep8 [kobakoba0723@fedora13-intel64 ~]$ which pep /usr/bin/which: no pep in (/home/kobakoba0723/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin) [kobakoba0723@fedora13-intel64 ~]$
今の状態はenv_pathを固定でやってしまっているので、
シェル変数$PATHから値を持って来れるようになれば良いんだけどなぁ。
[kobakoba0723@fedora13-intel64 ~]$ cat searchcmd.py import os def search_command(command, search_path, path_sep=os.pathsep): for path in search_path.split(os.pathsep): candidate = os.path.join(path, command) if os.path.isfile(candidate): return os.path.abspath(candidate) if __name__ == '__main__': import sys if len(sys.argv) != 2: print 'Usage: python searchcmd.py <command>' sys.exit(1) search_cmd = sys.argv[1] env_path = ['/home/kobakoba0723/bin', '/usr/local/bin', '/usr/bin', '/usr/local/sbin', '/usr/sbin', '/sbin'] search_path = os.pathsep.join(env_path) cmd_path = search_command(search_cmd, search_path) if cmd_path: print "Command '%s' found in '%s'" % (search_cmd, cmd_path) else: print "Command '%s' not found in '%s'" % (search_cmd, search_path) [kobakoba0723@fedora13-intel64 ~]$ python searchcmd.py pep8 Command 'pep8' found in '/home/kobakoba0723/bin/pep8' [kobakoba0723@fedora13-intel64 ~]$ python searchcmd.py pep Command 'pep' not found in '/home/kobakoba0723/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin' [kobakoba0723@fedora13-intel64 ~]$
参考サイト
モジュールインデックス@Python 2.6.2 document
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る
Pythonクックブック(2章)
ファイル操作の続き
zipファイルを扱う(zipfile, tempfile)
zipfileモジュールを使うとzipファイルの内容物を表示したり、展開したりできる。
ZipFile.namelist()を使うと内容物の名前を取得できるけど、
ZipFile.infolist()を使うと内容物に関する名前とかサイズとか更新日なんかも取得できる。
>>> import zipfile >>> z = zipfile.ZipFile("xml_parse.zip", "r") >>> for info in z.infolist(): ... print 'File:', info.filename, 'has', info.file_size, 'bytes' ... File: xml_parse/ has 0 bytes File: xml_parse/comps.xml has 1726498 bytes File: xml_parse/filelists.xml has 35256400 bytes File: xml_parse/sax_parser.py has 6532 bytes >>>
tempfileモジュールを使うと一時ファイルを作成することが出来る。
tempfile.mkstemp()を使うと一時ファイルを作成できるけど、使い終わったら自分で消さないといけない。
tempfile.NamedTemporaryFile()だと使い終わったら自動的に消してくれる。
tempfile.NamedTemporaryFile()とtempfile.TemporaryFile()の違いは、ファイルの名前があるのかないのか。
>>> import zipfile, tempfile, sys >>> file = tempfile.NamedTemporaryFile(mode='w+t', suffix='.zip') >>> file.name '/tmp/tmpcbTHIk.zip' >>> z = zipfile.ZipFile(file.name, 'w') >>> z.writestr('hello.py', 'def f(): return "hello world from "+__file__\n') >>> z.close() >>> sys.path.insert(0, file.name) >>> import hello >>> print hello.f() hello world from /tmp/tmpcbTHIk.zip/hello.py >>>
でもなんで/tmp/tmpcbTHIk.zip内のhello.pyを直接インポートできるのかわからない。
zipfileモジュールを一切介さずインポートしようとするとエラーが出るから、zipfileモジュールが関連してるんだろうな。
>>> import sys >>> sys.path.insert(0, '/home/kobakoba0723/hello_world.zip') >>> import hello Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named hello >>> [kobakoba0723@fedora13-intel64 ~]$ ls TestTool cedet-1.0.tar.gz lib テンプレート 画像 TestTool.bak exec.data search_string デスクトップ 公開 anaconda ez_setup.py virtual-python.py ドキュメント bin hello_world.zip xml_parse.zip ビデオ cedet-1.0 include ダウンロード 音楽 [kobakoba0723@fedora13-intel64 ~]$ unzip hello_world.zip Archive: hello_world.zip creating: hello_world/ inflating: hello_world/hello.py [kobakoba0723@fedora13-intel64 ~]$
tarファイルを扱う(tarfile)
tarfileモジュールを使うことで、作成から展開まで行える。
[kobakoba0723@fedora13-intel64 ~]$ cat make_tar.py import tarfile import os def make_tar(folder_to_backup, dest_folder, compression='gz'): if compression: dest_ext = '.' + compression else: dest_ext = '' arcname = os.path.basename(folder_to_backup) dest_name = '%s.tar%s' % (arcname, dest_ext) dest_path = os.path.join(dest_folder, dest_name) if compression: dest_cmp = ':' + compression else: dest_cmp = '' out_file = tarfile.open(dest_path, 'w' + dest_cmp) # out_file.add(folder_to_backup) out_file.add(folder_to_backup, arcname) out_file.close() return dest_path def listup_tar(filename): in_file = tarfile.open(filename, 'r') print in_file.list() def unpack_tar(filename): in_file = tarfile.open(filename, 'r') in_file.extractall(path='./unpack') if __name__ == '__main__': filename = make_tar('/home/kobakoba0723/search_string', '/home/kobakoba0723/', 'gz' ) print filename listup_tar(filename) unpack_tar(filename)
tarfile.addの第2引数を指定しなければ、dest_pathをトップから全てzipにしてくれる。
第2匹数を指定すれば、指定したところからzipにしてくれる
[kobakoba0723@fedora13-intel64 ~]$ ls TestTool cedet-1.0 include unpack デスクトップ 画像 TestTool.bak cedet-1.0.tar.gz lib virtual-python.py ドキュメント 公開 anaconda exec.data make_tar.py ダウンロード ビデオ bin ez_setup.py search_string テンプレート 音楽 [kobakoba0723@fedora13-intel64 ~]$ ls unpack/ [kobakoba0723@fedora13-intel64 ~]$ python make_tar.py /home/kobakoba0723/search_string.tar.gz -rwxrwxr-x kobakoba0723/kobakoba0723 0 2011-06-22 23:02:23 search_string/ -rw-rw-r-- kobakoba0723/kobakoba0723 56 2011-04-10 18:14:20 search_string/snmpd.options -rw-r--r-- kobakoba0723/kobakoba0723 1549 2011-04-10 17:26:47 search_string/profile -rw-rw-r-- kobakoba0723/kobakoba0723 547 2011-04-10 18:26:35 search_string/search_string.py None [kobakoba0723@fedora13-intel64 ~]$ ls unpack/ search_string [kobakoba0723@fedora13-intel64 ~]$
参考サイト
モジュールインデックス@Python 2.6.2 document
- 作者: Alex Martelli,Anna Martelli Ravenscroft,David Ascher,鴨澤眞夫,當山仁健,吉田聡,吉宗貞紀
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/06/26
- メディア: 大型本
- 購入: 11人 クリック: 423回
- この商品を含むブログ (85件) を見る