はてブロ@ama_ch

https://twitter.com/ama_ch

今日のPython

スレッドのロック

p.374 RLockオブジェクトを使ってクリティカルセクション(ロック〜アンロック)を作る例

lock = threading.RLock()  #クリティカルセクションを開始
try:
    # スレッドの実行コード
finally:
    lock.release()  #ロックを解放

pythonでCGIを利用する

事前準備 - Macでサーバー環境を整える

CGIを動かす前に、ローカルでサーバーとして動く環境を作る。MacはOS X 10.5.2

Apacheを稼働

Macでは最初からApacheが入っているので、これを稼働させる。
システム環境設定 -> 共有 -> Web共有 をオン
この状態でhttp://127.0.0.1/ もしくは http://localhost/ にアクセスし、Apacheが動いていることを確認する。

ファイルの置き場所について

ローカルサーバ上で参照されるファイルのアドレスは、
htmlなどのファイル:/Library/WebServer/CGI-Executables/Documents
CGI:/Library/WebServer/CGI-Executables/

スクリプトファイル

p.379

#!/Library/Frameworks/Python.framework/Versions/Current/bin/python
# -*- coding: utf-8 -*-
import cgi 
import cgitb; cgitb.enable()
import calendar
import time
calendar.setfirstweekday(6)  #カレンダーの最初の曜日を日曜日に設定

year, month = time.localtime()[:2]

form = cgi.FieldStorage()  #CGIに渡されたデータを取得
year = int(form.getvalue("year", year))
month = int(form.getvalue("month", month))

# 西暦、月、曜日を表示
b = """<tr><th colspan="7">%d,%d</td></tr>""" % (year, month)
b += "<tr>"
for wname in ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]:
    b += "<th>%s</td>" % wname
b += "</tr>"

# カレンダーを表示
for week in calendar.monthcalendar(year, month):
    b += "<tr>\n"
    for day in week:
        if day: b += "<td>%d</td>" % day;
        else:   b += "<td>&nbsp;</td>";  #半角スペース

# ヘッダ、HTMLを出力
print "Content-type: text/html\n"
print "<html><body>"
print """<table border="1"> %s </table>""" % b
print "</body></html>"

1行目は、ターミナルで「$ which python」と入力し、表示された値。今までの「#!/usr/bin/env python」だとうまく動かなかった。
これをtest.cgiなどの名前で保存し、/Library/WebServer/CGI-Executables/に設置する。
次にパーミッションを変更する。以下のコマンドで。
$ chmod 755 /Library/WebServer/CGI-Executables/test.cgi


http://127.0.0.1/cgi-bin/test.cgiへアクセス。実行結果が表示される。





2008,5
SunMonTueWedThuFriSat
    123
45678910
11121314151617
18192021222324
25262728293031

PythonでCGI動いたよ!やったー!

プログラムのテスト

doctestモジュール

p.388

#!/usr/bin/env python
# -*- coding: utf-8 -*-
''' complete.py
完全数を探す
'''

def get_divisor(number):
    """ 約数を探してリストにして返す
    >>> import complete
    >>> complete.get_divisor(2)
    [1]
    >>> complete.get_divisor(6)
    [1, 2, 3]
    >>> complete.get_divisor(100)
    [1, 2, 4, 5, 10, 20, 25, 50]
    """
    return [cnt for cnt in range(1, number) if number % cnt == 0]

def is_complete(number):
    """ 数値が完全数かどうか調べ、boolで返す
    >>> import complete
    >>> complete.is_complete(6)
    True
    >>> complete.is_complete(428)
    False
    >>> complete.is_complete(496)
    True
    """
    if sum(get_divisor(number)) == number:  return True;
    else:                                   return False;

if __name__ == "__main__":
    import doctest     #doctestモジュールをインポートする
    doctest.testmod()  #doctestを実行する
    for cnt in xrange(1, 1001):
        if is_complete(cnt):
            print cnt,

インタラクティブシェルでスクリプトをモジュールとして読み込み、関数単位?での実行結果をスクリプト内にコメントとして貼り付けておくと、doctestモジュールがその結果と照らし合わせてくれる。
普通、ファイルとして実行した場合にテストを行うので、doctestはif __name == "__main__":ブロック内に記述する。



実行結果:成功例(普通に実行される)

$ python complete.py
6 28 496

実行結果:失敗例

$ python complete.py
**********************************************************************
File "complete.py", line 12, in __main__.get_divisor
Failed example:
    complete.get_divisor(5)
Expected:
    [1, 2, 3]
Got:
    [1]
**********************************************************************
1 items had failures:
   1 of   4 in __main__.get_divisor
***Test Failed*** 1 failures.
6 28 496

SQLiteを利用する

python2.5ではsqlite3というモジュールがあるので、それを利用する。


p.404 PythonSQLiteを使ったサンプルプログラム

#!/usr/bin/env python
# -*- coding: utf-8 -*-
''' sqltest.py
SQLiteのサンプルプログラム 郵便番号と住所を管理する
'''
import sqlite3

# 郵便番号のリスト
postno = [[u"東京都千代田区", "100-0000"],
         [u"東京都千代田区飯田橋", "102-0072"],
         [u"東京都千代田区一番町", "102-0082"],
         [u"東京都千代田区岩本町", "101-0032"],]

# コネクションオブジェクトを作る
con = sqlite3.connect(":memory:")
cur = con.cursor()  #カーソルを作る

# テーブルを作成
cur.execute("""CREATE TABLE postdb(address text, postno text)""")

# データを登録
for item in postno:
    cur.execute("""INSERT INTO postdb(address, postno) VALUES(?,?)""", item)

# データを選択、表示
cur.execute("SELECT * FROM postdb WHERE postno=?", ("102-0072",))
data = cur.fetchone()
print data[1], data[0]

実行結果

$ python sqltest.py
102-0072 東京都千代田区飯田橋

SQLを理解していないから色々いじることができない・・・今後の課題。


GUIアプリケーション

Tkinterを使ったGUI構築サンプル

p.435

#!/usr/bin/env python
# -*- coding: utf-8 -*-
''' tkinter.py
GUIアプリケーションのサンプル
'''
from Tkinter import *
import time

class App(Frame):
    TIME = 10 * 3  #タイマー待ち時間
    def __init__(self, master=None):
        "初期化用メソッド"
        Frame.__init__(self, master)
        self.time = 0
        self.master.title("Tk Timer")  #フレームタイトル
        self.timestr = StringVar()
        self.timestr.set("00:30")
        l = Label(self, textvariable=self.timestr,
                  font=('Halvetica', '48', 'bold'))
        b1 = Button(self, text="Start", command=self.countdown)
        b2 = Button(self, text="Quit", command=self.master.destroy)
        for obj, sideparam in ((l, TOP), (b1, LEFT), (b2, RIGHT)):
            obj.pack(side=sideparam)
        self.pack()

    def countdown(self):
        "タイマーの時間を減らしていくメソッド"
        if self.time == 0:
            self.time = time.time()
        timeleft = max(self.TIME-(time.time()-self.time), 0)
        min, sec = (timeleft) / 60, timeleft % 60
        self.timestr.set("%02d:%02d" % (min, sec))
        self.after(1000, self.countdown)

if __name__ == "__main__":
    app = App()
    app.mainloop()

とりあえずソースだけ。Tkinterモジュールを使うとGUIアプリが作れます。すげえええ


みんPyおわり!

後半かなり駆け足だったけど、ひとまずみんなのPythonは読み終えました。基本的な文法やモジュールの使い方は理解できたので、あとは自分の考えたものを作れるようにゴリゴリ書いていきます。これにて「今日のPython」シリーズは、終わりです。


学習開始日:4/22 - Python始めました


何日かかったかな?

>>> import datetime
>>> d1 = datetime.date(2008, 4, 22)
>>> d2 = datetime.date(2008, 5, 15)
>>> print d2 - d1
23 days, 0:00:00

23日かかりました!datetimeモジュールも大変便利ですね。それではごきげんよう。




みんなのPython

みんなのPython