2013/07/29

Python Tips:Pythonのイースターエッグ

Pythonのイースターエッグについてご紹介します。

・・・の説明の前に、まずは「イースターエッグ」について。イースターエッグとは、開発者の遊び心で作られた隠し機能のことです。Wikipediaのページでは次のように説明されています。

イースター・エッグ(Easter egg)とは、コンピュータのソフトウェア・書籍・CDなどに隠されていて、本来の機能・目的とは無関係であるメッセージや画面の総称である。ユーモアの一種である。
これらを「イースター・エッグ」と呼ぶのは、キリスト教の復活祭の際に、装飾した卵(イースター・エッグ)をあちこちに隠して子供たちに探させる遊びにちなむ。
個人的には、もともとの卵を探す遊びの方を知らないので、イースターエッグといえばこちらのイースターエッグが思い浮かびます。

Pythonにもイースターエッグが存在するようです。以下、いくつか見ていきます(これから知る方にとってネタバレにならないよう、やり方だけ・・・)。

import this

import this
# 以下のとおり表示
# The Zen of Python, by Tim Peters
# 
# Beautiful is better than ugly.
# Explicit is better than implicit.
# ...
「import this」とやると、「The Zen of Python」(禅オブPython)がズラズラーっと表示されます。

import hello

import __hello__
import __phello__
プログラマの最初の一歩といえば「Hello world」ですよね。なぜ、「phello」でもHello worldなのかわかりませんが、、「print hello = phello」、でしょうか。

from __future__ import braces

from __future__ import braces
これはPythonのインデント構文にまつわるイースターエッグです。

他の言語でよくある {} ーーいわゆる braces を使ったブロック表現を import します、という意味の import 文。結果は「ありえないっす!」的なニュアンスでしょうか。「インデントによるブロックがこんなにイケてるのに {} なんて導入するわけないじゃん!」的な感じなのかな。

import antigravity

import antigravity
これは、やってみてのお楽しみ。antigravityは「反重力」的な意味です。

love is...

最後に、これはイースターエッグではないのですが、Pythonインタプリタを使ったことば遊びとしてPythonメーリングリスト上で紹介されたそうです。

>>> import this
...
>>> love = this
>>> this is love
True
>>> love is True
False
>>> love is False
False
>>> love is not True or False
True
>>> love is not True or False; love is love
True
True

以上です。


参考
Easter eggs in Python

2013/07/22

ライブラリ:timeit

Pythonの「timeit」というライブラリについてご紹介します。

import timeit

「timeit」は実行時間を計測するためのライブラリです。

スクリプト内で使うこともコマンドラインからも使うこともできます。以下、順に見ていきます。

スクリプト内で

import timeit

# Timerインスタンスを生成
# Timer(時間を計測したい処理, 前処理)
t = timeit.Timer("math.sin(10)", "import math")

# 時間を実際に計測
print t.timeit() # 0.45...など
時間を計測するには、Timerクラスのインスタンスを生成した後timeit()メソッドを実行すれば行うことができます。

Timerクラスを生成するときは、「時間を計測したい処理」と、その最初に実行したい「前処理」を与えます。デフォルトでは100万回実行されたときの合計時間が返ってきます。

時間の単位は現実世界の秒やマイクロ秒(wall clock time)などで、CPU時間(CPU time)ではありません。

print t.timeit(1000)
timeit()に整数を渡すと、実行回数を変更することもできます。この場合は1000回の繰り返しとなります。

print min(t.repeat(5))
repeat()は、timeitによる計測をn回連続で行い、結果を長さnのリストに格納して返してくれます。この場合は長さ5のリストが返ってきます。

timeit()が返す数値は他の実行中のプロセスなどによって変わったりもするため、複数回試した場合は、その平均値よりも最小値(min)を見ておくのがよいそうです。

the min() of the result is probably the only number you should be interested in.

つづいて、コマンドライン上での使い方について。

コマンドラインから

$python -m timeit "[str(x) for x in range(100)]"
10000 loops, best of 3: 63.7 usec per loop
コマンドラインから使う場合は、「python -m timeit」のあとにオプションをつけて使います。デフォルトでは、3回実行したうちの最小の時間が帰ってきます。

python -m timeit -n 10 -r 5 -s "import math" "[math.sin(x) for x in range(1000)]"
オプション「n」で1試行あたりの実行回数、「r」で試行回数、「s」で前処理を指定することができます。この場合であれば、処理を10回連続で実行したときの時間を5回計測し、そのうちの最短の時間を返してくれます。

ほかにもオプションがありますので、詳しくは公式ドキュメントをご参照ください。

以上です。


参考
timeit - Python公式ドキュメント
How to use timeit correctly - stackverflow
timeit – 小さな Python コードの実行時間を計る - Python Module of the Week

2013/07/20

ライブラリ:calendar

Pythonの「calendar」というライブラリについてご紹介します。

import calendar

「calendar」は、名前のとおりカレンダー情報を扱うためのライブラリです。中身はとてもシンプルで、「何年何月」という形で特定の月を指定すればその月の日・曜日情報を返す、といった機能がメインです。

もっと広い範囲で日付や時間の情報を扱いたい場合は「datetime」や「time」といったライブラリが便利です。

以下、主な機能を見ていきます。

month()

imort calendar

print calendar.month(2013, 8)
# 次のとおり表示される
#     August 2013
# Mo Tu We Th Fr Sa Su
#           1  2  3  4
#  5  6  7  8  9 10 11
# 12 13 14 15 16 17 18
# 19 20 21 22 23 24 25
# 26 27 28 29 30 31
month()は、年と月を整数で渡せば、その月のカレンダーを文字列として返してくれる関数です。

print type(calendar.month(2013, 8)).__name__
# strと表示される
返ってくる中身は通常の文字列です。

Calendar

c1 = calendar.Calendar()

print type(c1).__name__  # Calendar
カレンダーをひとつ表示するだけであればmonth()で十分ですが、ちょっと複雑な(といってもシンプルですが)カレンダー情報を扱うのであればCalendarクラスを利用するのが便利です。

for ele in c1.iterweekdays():
    print ele,
# 0 1 2 3 4 5 6 と表示される
インスタンスメソッドiterweekdays()は、曜日を表す0から6の数字を生成してくれるイテレータです。0が月曜日、6が日曜日に対応しています。

c2 = calendar.Calendar(firstweekday=5)
for ele in c2.iterweekdays():
    print ele,
# 5 6 0 1 2 3 4 と表示される
始まりの曜日はデフォルトでは月曜日となっていますが、変えたい場合はオプションfirstweekdayが利用できます。

for ele in c1.itermonthdays2(2013, 8):
    print '(%2d,%2d)' % (ele[0], ele[1]),
    if ele[1] == 6:
        print
# 次のとおり表示される
# ( 0, 0) ( 0, 1) ( 0, 2) ( 1, 3) ( 2, 4) ( 3, 5) ( 4, 6)
# ( 5, 0) ( 6, 1) ( 7, 2) ( 8, 3) ( 9, 4) (10, 5) (11, 6)
# (12, 0) (13, 1) (14, 2) (15, 3) (16, 4) (17, 5) (18, 6)
# (19, 0) (20, 1) (21, 2) (22, 3) (23, 4) (24, 5) (25, 6)
# (26, 0) (27, 1) (28, 2) (29, 3) (30, 4) (31, 5) ( 0, 6)
itermonthdays2()は、年・月を渡すとその月のすべての(日, 曜日)を返してくれるメソッドです。

その月の「最初の日を含む週の最初の日」から「最後の日を含む週の最後の日」までの日付が返ってくるため、要素数は必ず7の倍数です。また、その月に属さない日の日付部分はすべて0となります。

名前に「2」のつかないitermonthdays()というメソッドもあって、こちらは曜日情報を含まない日付の部分のみをリストで返します。

for ele in c1.itermonthdates(2013, 8):
    print ele
# 次のとおり表示される
# 2013-07-29
# 2013-07-30
# 2013-07-31
# 2013-08-01
# 2013-08-02
# ...
# 2013-08-31
# 2013-09-01
# print type(ele).__name__  # datetime.date
itermonthdays2()は各要素を(日, 曜日)というフォーマットで返しましたが、itermonthdates()は各要素をdatetimeライブラリのdatetime.date型のインスタンスとして返します。

c3 = c1.monthdays2calendar(2013, 8)
for week in c3:
    print week
# 次のとおり表示される
# [(0, 0), (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6)]
# [(5, 0), (6, 1), (7, 2), (8, 3), (9, 4), (10, 5), (11, 6)]
# [(12, 0), (13, 1), (14, 2), (15, 3), (16, 4), (17, 5), (18, 6)]
# [(19, 0), (20, 1), (21, 2), (22, 3), (23, 4), (24, 5), (25, 6)]
# [(26, 0), (27, 1), (28, 2), (29, 3), (30, 4), (31, 5), (0, 6)]
itermonthdays2()はすべての日付をフラットに返しましたが、monthdays2calendar()は、itermonthdays2()が返す要素を週単位に分けて返してくれます。

c4 = c1.monthdatescalendar(2013, 8)
print len(c4)  # 5
print c4[0][0]  # 2013-07-29
monthdays2calendar()と同様に、datetime.dateを週単位にまとめて返してくれるmonthdatescalendar()というメソッドもあります。週単位にまとめるのでlen(c4)は5(5週)となっています。

メインとなるのはこのCalendarクラスですが、その他にも、カレンダーを表示することに特化したTextCalendar、HTMLCalendarというクラスが用意されています。

TextCalendar

c5 = calendar.TextCalendar()
print c5.formatmonth(2013, 8, w=3)
print c5.formatyear(2013)
TextCalendarは、カレンダー情報をテキストとして出力するためのクラスです。formatmonth()は月単位、formatyear()は年単位で次のような整形されたカレンダーを出力することができます。

#         August 2013
# Mon Tue Wed Thu Fri Sat Sun
#               1   2   3   4
#   5   6   7   8   9  10  11
#  12  13  14  15  16  17  18
#  19  20  21  22  23  24  25
#  26  27  28  29  30  31

HTMLCalendar

TextCalendarがプレーンテキストに表示するのに対し、HTMLカレンダーは、タグ付きのHTMLフォーマットのカレンダーを出力します。
FILEOUT = 'sample_calendar.html'

c3 = calendar.HTMLCalendar()

f = open(FILEOUT, 'w')
f.write(c3.formatmonth(2013, 8))
f.close()

以上です。


参考
calendar - Python公式ドキュメント
Python Date & Time - tutorialpoint

2013/07/18

ライブラリ:time

Pythonの「time」というライブラリについてご紹介します。

import time

「time」は、時間関連の情報や関数を集めたライブラリです。もちろん用途によって変わってはくるかと思うのですが、頻度の高い使いどころとしては次のようなものがあるでしょうか。
  • システムの現在時刻を取得する
  • 時刻形式のデータを生成する
  • 時刻のフォーマットを変更する
  • スリープ

以下、順番に見ていきます。

・・・の前にひとつ前置きを。

以下、epoch(エポック)ということばが出てきますが、これは「原点となる時点」を表すことばとして使っています。たとえば、西暦であれば西暦0年1月1日の0時がエポックですし、平成であれば平成元年1月1日の0時がエポックといえます。Unixの世界では、これが1970年の1月1日0時に設定されており、そこからの経過秒数がベースとなっています。公式ドキュメントにも説明が載っています

それでは以下、順番に。

システムの現在時刻を取得する

print time.time()  # epochからの秒数を返します
epochからの時間を秒数で得るにはtime()を使います。

print time.gmtime()
# 現在のUTC(元グリニッジ標準時)を
# time.struct_timeオブジェクトとして返します
人間にとってわかりやすい年・月・日という形式の時刻情報を取得するには、gmtime()を使います。これは、time.struct_timeという形式で現在時刻を返してくれます。

print time.gmtime().tm_year  # 2013 現在の年を4桁で返します
struct_timeは年・月・日・時・分・秒などの情報をアトリビュートとして持ったオブジェクトです。年・月・日など以外にも、曜日、その年の頭から数えての経過日数、サマータイムに関するフラグなどの情報も持っています。それぞれ名前は次のとおりとなっています。
  • tm_year 年
  • tm_mon 月
  • tm_mday 日
  • tm_hour 時
  • tm_min 分
  • tm_sec 秒
  • tm_wday 曜日を0~6で表した数値
  • tm_yday 年の頭から数えた経過日数
  • tm_isdst サマータイムのフラグ
公式ドキュメントの該当するパートもよろしければごらんください。

print time.localtime()
# 設定されたタイムゾーンにおける現在の時刻を返します
# gmtime()と同じく、time.struct_time形式で返します

時刻形式のデータを生成する

print time.struct_time([2013, 1, 1, 1, 10, 15, 1, 1, 0])
# time.struct_time([tm_year=2013, tm_mon=1, tm_mday=1, tm_hour=1, tm_min=10, tm_sec=15, tm_wday=1, tm_yday=1, tm_isdst=0])
時刻形式形式のデータを生成するには、time.struct_timeに時刻情報が入ったリストを渡します。時刻情報は、上述の年・月・日などの9つの情報となります。

時刻のフォーマットを変更する

t = time.localtime()
print time.mktime(t)  # epochからの秒数
struct_time形式の時刻を「epochからの秒数」に変換するには、mktime()を使います。1秒以下の精度でも時間を計測することができます。

sec = time.time()
print time.gmtime(sec)  #  UTCでの時間
print time.localtime(sec)  #  ローカルのタイムゾーンでの時間
逆に、「epochからの秒数」を年・月・日・・・形式に変換するには、gmtime()、localtime()に引数を与えて使います。

t = time.localtime()
print time.strftime("year:%Y week:%W", t)
# year:2013 week:30 などと返されます
struct_time形式の時間をフォーマット指定で文字列に変換するには、strftime()を使います。

tstr = "2013 08 01"
print time. strptime(tstr, "%Y %m %d")
# time.struct_time(tm_year=2013, tm_mon=8, ...
文字列を読み取ってstruct_time形式に変換するには、strptime()を使います。引数のひとつめに文字列を、ふたつめにフォーマットを渡します。

strftime()とstrptime()のフォーマットにおける規則はこちらに一覧が載っています。
http://docs.python.org/2/library/time.html#time.strftime

スリープ

time.sleep(3.5)  # 3.5秒停止
Pythonプロセスの実行を一定時間停止するには、sleep()を使います。引数の単位は「秒」です。



インストール
timeはPython本体をインストールすれば最初から入っているため、別途インストールは必要ありません。


参考
time - Python公式ドキュメント

2013/07/06

ライブラリ:datetime

Pythonの「datetime」というライブラリについてご紹介します。

import datetime

「datetime」は、時間に関するデータを取り扱うためのライブラリです。Pythonの標準モジュールとしてPythonに同梱されています。

時間情報を扱う同様のライブラリとして「time」「calendar」などがあります。timeとdatetimeはよく似ているのですが、datetimeは

  • よりシンプル
  • 日付の部分と時間の部分を分けられる
  • 時刻の差分(日付 - 日付)が手軽に取り扱える

などのポイントがtimeと異なる点かと思います。

以下、おもな機能を見てみます。

datetimeのデータ型

import datetime

print datetime.datetime.__name__  # datetime
print datetime.date.__name__  # date
print datetime.time.__name__  # time
datetimeには、datetime、date、timeという3つのタイプのデータ型があります。名前のとおり、datetimeは日付と時刻をまとめた時間、dateは日付のみ、timeは時刻のみを扱うオブジェクトです。

print datetime.timedelta.__name__  # timedelta
また、日付間、時刻間の差分を表す型として、timedeltaというものが用意されています。

datetime

datetimeは、年、月、日、時間、分、秒、マイクロ秒(100万分の1秒)という情報を持ったデータ型です。
t1 = datetime.datetime(2013,8, 5, 3 ,50 ,25)
t2 = datetime.datetime.today()

print t1  # 2013-08-05 03:50:25 と表示される
print t2  # t1と同じフォーマットで現在時刻が表示される
datetime(年, 月, 日, ...)という形式でインスタンスを作ることができます。メソッドtoday()を使うと、現在の日・時を得ることができます。

import time
t3 = datetime.datetime.fromtimestamp(time.time())
print t3  # t1と同じフォーマットで現在時刻が表示される
fromtimestamp()というメソッドを使えば、time.time()が返すような、1970年1月1日0時からの経過秒数で表された時刻フォーマット(POSIXタイム)をdatetime形式に変換することができます。

t4 = datetime.datetime.strptime('2013 08 05', '%Y %m %d')
print t4  # 2013-08-05 00:00:00 と表示される
文字列で表された時刻をdatetime型に変換するには、strptime()を使います。

年や月などの情報にアクセスするには、アトリビュートやメソッドを使います。
print t2.year  # 年
print t2.month  # 月
print t2.day  # 日
print t2.hour  # 時
print t2.minute  # 分
print t2.second  # 秒
print t2.microsecond  # マイクロ秒
print t2.weekday()  # 曜日を表す0から6の数字

「-」演算子を使うことで、2時刻間の差分も簡単に得ることができます。
d1 = t1 - t2
print type(d1).__name__  # timedelta
print d1  # 32 days, 15:25:33.... などと表示される
差分を取ることで、timedeltaインスタンスが自動的に生成されます。

datetime型の変数に「+」「-」演算子でtimedeltaを加えることで、元の日付にその差分を加えた日付を得ることも可能です。
d2 = datetime.timedelta(days=350)
t3 = t1 + d2
print type(t3).__name__  # datetime
print t3  # t1にd2を追加した時間が表示される

date

t5 = datetime.date(2013, 10, 12)
t6 = datetime.date.today()

print t5  # 2013-10-12
print t5  # t5と同じフォーマットで本日の日付
dateは、日付部分――年・月・日の情報のみを持ったデータ型です。ちょうど、datetimeが持つパラメータや機能のうち時刻の部分を取っ払って日付に関する部分だけを抽出したような内容となっています。

データとしては日付部分だけしか見なくてdatetimeは冗長だ、といった場合なんかには便利かと思います。

time

t7 = datetime.time(7, 5 ,37)
print t7
dateとは逆に、日付部分を取っ払い、1日のうちの時刻の部分――時・分・秒・マイクロ秒のみを持ったデータ型がtimeです。

timeはdatetime、timeと比べて機能がシンプルで、today()やnow()なども用意されていないようです。

以上です。

ほかにも、タイムゾーンを表現する「tzinfo」や「timezone」といったオブジェクト、フォーマットの変換機能なんかも用意されていておもしろいので、詳しくは公式ドキュメントをごらんになってください。


インストール
「datetime」は標準モジュールとしてPythonに同梱されているので、別途インストールの必要はありません。


参考
datetime - Python公式ドキュメント
datetime - Doug Hellmann
日付の処理いろいろ - GeSource