<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2114684746269128159</id><updated>2011-07-29T14:23:12.489+09:00</updated><title type='text'>残高照会メモ</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>72</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8581637161968598001</id><published>2010-06-21T22:45:00.002+09:00</published><updated>2010-06-24T13:04:28.076+09:00</updated><title type='text'>python自習テキスト</title><content type='html'>wikiで書き始めた。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://giraffe.topaz.ne.jp/wiki/doku.php/py:python_curriculum"&gt;http://giraffe.topaz.ne.jp/wiki/doku.php/py:python_curriculum&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8581637161968598001?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8581637161968598001/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8581637161968598001' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8581637161968598001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8581637161968598001'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2010/06/python.html' title='python自習テキスト'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7283436824467007296</id><published>2010-03-18T20:54:00.003+09:00</published><updated>2010-03-18T21:01:00.174+09:00</updated><title type='text'>pythonでハフマン符号化</title><content type='html'>データの出力頻度をもとに、一つずつのデータを可変長にエンコードする。&lt;br /&gt;適当なファイルを filename 変数に入れて実行すると、いろいろ出力が変わる。&lt;br /&gt;ハフマン符号の正規化とかいう処理はしていないので、ツリーの散らばり具合はいいかげん。&lt;br /&gt;&lt;br /&gt;出力例は、"The Brothers Karamazov" の全テキストを突っ込んでみたときのもの。&lt;br /&gt;この手法を素直に使うだけでは、そんなに高い効率の圧縮にはならないということかな。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- coding:cp932 -*-&lt;br /&gt;&lt;br /&gt;filename = r'any_file.txt'&lt;br /&gt;&lt;br /&gt;# 出現頻度取得&lt;br /&gt;freq = dict()&lt;br /&gt;for line in open(filename, 'rb'):&lt;br /&gt;  for c in line:&lt;br /&gt;    freq.setdefault(c, 0)&lt;br /&gt;    freq[c] += 1&lt;br /&gt;&lt;br /&gt;# 頻度が少ないものから順に枝をまとめてツリー形成&lt;br /&gt;wtree = [i for i in freq.iteritems()]&lt;br /&gt;while len(wtree) &gt; 1:&lt;br /&gt;  # 出現頻度ワースト2の枝を見つけてまとめる&lt;br /&gt;  wtree.sort(lambda a,b: cmp(b[1], a[1]))&lt;br /&gt;  b2, b1 = (wtree.pop(), wtree.pop())&lt;br /&gt;  wtree.append(((b1[0], b2[0]), b1[1] + b2[1]))&lt;br /&gt;&lt;br /&gt;tree = wtree[0][0]&lt;br /&gt;print "frequency tree:"&lt;br /&gt;print tree&lt;br /&gt;orig_bits = wtree[0][1] * 8&lt;br /&gt;&lt;br /&gt;# ツリーをもとに変換表生成&lt;br /&gt;def collapse_tree(t, leaf, prefix):&lt;br /&gt;  if type(leaf) == tuple:&lt;br /&gt;    c = 0&lt;br /&gt;    for i in leaf:&lt;br /&gt;      collapse_tree(t, i, prefix + (c,))&lt;br /&gt;      c += 1&lt;br /&gt;  else:&lt;br /&gt;    t.append((leaf, prefix))&lt;br /&gt;&lt;br /&gt;e_table = []&lt;br /&gt;collapse_tree(e_table, tree, ())&lt;br /&gt;&lt;br /&gt;# 変換表印字&lt;br /&gt;compressed_bits = 0&lt;br /&gt;print "encoding table:"&lt;br /&gt;for i in e_table:&lt;br /&gt;  print "".join([str(j) for j in i[1]]), (i[0], freq[i[0]])&lt;br /&gt;  compressed_bits += freq[i[0]] * len(i[1])&lt;br /&gt;&lt;br /&gt;print "data can be compressed from %d bits into %d bits (%f%%)" % \&lt;br /&gt;  (orig_bits, compressed_bits, float(compressed_bits) / orig_bits)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;出力例：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;frequency tree:&lt;br /&gt;(((' ', (('s', (('.', ('I', (((('z', 'L'), 'G'), '!'), (('P', 'q'), ((('E', ('V'&lt;br /&gt;, ('U', (('4', '0'), ('3', '5'))))), 'C'), ';'))))), ('p', 'b'))), ('r', ('m', '&lt;br /&gt;y')))), (('t', ((('v', ("'", (('-', 'x'), 'A'))), 'w'), 'd')), ((('\n', '\r'), (&lt;br /&gt;'c', ',')), ('l', ('f', 'g'))))), ((('o', 'a'), ('n', (((((('S', 'M'), (('K', ('&lt;br /&gt;R', ':')), 'W')), ('T', (('D', ((('Z', 'J'), ')'), ('(', (('*', (('8', '7'), 'Q'&lt;br /&gt;)), (('2', (('X', '9'), '6')), '1'))))), 'B'))), 'k'), ('"', (((('O', 'N'), 'F')&lt;br /&gt;, 'H'), ('?', ('j', 'Y'))))), 'u'))), (('h', 'i'), 'e')))&lt;br /&gt;encoding table:&lt;br /&gt;000 (' ', 349903)&lt;br /&gt;00100 ('s', 87812)&lt;br /&gt;0010100 ('.', 22205)&lt;br /&gt;00101010 ('I', 10989)&lt;br /&gt;001010110000 ('z', 730)&lt;br /&gt;001010110001 ('L', 675)&lt;br /&gt;00101011001 ('G', 1352)&lt;br /&gt;0010101101 ('!', 2687)&lt;br /&gt;00101011100 ('P', 1293)&lt;br /&gt;00101011101 ('q', 1279)&lt;br /&gt;0010101111000 ('E', 339)&lt;br /&gt;00101011110010 ('V', 165)&lt;br /&gt;001010111100110 ('U', 69)&lt;br /&gt;00101011110011100 ('4', 17)&lt;br /&gt;00101011110011101 ('0', 16)&lt;br /&gt;00101011110011110 ('3', 16)&lt;br /&gt;00101011110011111 ('5', 15)&lt;br /&gt;001010111101 ('C', 592)&lt;br /&gt;00101011111 (';', 1171)&lt;br /&gt;0010110 ('p', 20938)&lt;br /&gt;0010111 ('b', 19549)&lt;br /&gt;00110 ('r', 78044)&lt;br /&gt;001110 ('m', 38521)&lt;br /&gt;001111 ('y', 37053)&lt;br /&gt;0100 ('t', 133524)&lt;br /&gt;0101000 ('v', 18431)&lt;br /&gt;01010010 ("'", 9357)&lt;br /&gt;0101001100 ('-', 2399)&lt;br /&gt;0101001101 ('x', 2172)&lt;br /&gt;010100111 ('A', 4190)&lt;br /&gt;010101 ('w', 32169)&lt;br /&gt;01011 ('d', 64044)&lt;br /&gt;011000 ('\n', 32018)&lt;br /&gt;011001 ('\r', 32018)&lt;br /&gt;011010 ('c', 31099)&lt;br /&gt;011011 (',', 30341)&lt;br /&gt;01110 ('l', 60812)&lt;br /&gt;011110 ('f', 30287)&lt;br /&gt;011111 ('g', 27884)&lt;br /&gt;1000 ('o', 117883)&lt;br /&gt;1001 ('a', 117275)&lt;br /&gt;1010 ('n', 99433)&lt;br /&gt;1011000000 ('S', 2028)&lt;br /&gt;1011000001 ('M', 2019)&lt;br /&gt;10110000100 ('K', 1027)&lt;br /&gt;101100001010 ('R', 517)&lt;br /&gt;101100001011 (':', 474)&lt;br /&gt;1011000011 ('W', 1918)&lt;br /&gt;101100010 ('T', 3586)&lt;br /&gt;10110001100 ('D', 972)&lt;br /&gt;10110001101000 ('Z', 132)&lt;br /&gt;10110001101001 ('J', 119)&lt;br /&gt;1011000110101 (')', 219)&lt;br /&gt;1011000110110 ('(', 219)&lt;br /&gt;101100011011100 ('*', 62)&lt;br /&gt;10110001101110100 ('8', 13)&lt;br /&gt;10110001101110101 ('7', 12)&lt;br /&gt;1011000110111011 ('Q', 23)&lt;br /&gt;1011000110111100 ('2', 21)&lt;br /&gt;101100011011110100 ('X', 6)&lt;br /&gt;101100011011110101 ('9', 5)&lt;br /&gt;10110001101111011 ('6', 10)&lt;br /&gt;101100011011111 ('1', 36)&lt;br /&gt;1011000111 ('B', 1725)&lt;br /&gt;1011001 ('k', 12741)&lt;br /&gt;1011010 ('"', 12521)&lt;br /&gt;10110110000 ('O', 861)&lt;br /&gt;10110110001 ('N', 785)&lt;br /&gt;1011011001 ('F', 1605)&lt;br /&gt;101101101 ('H', 3190)&lt;br /&gt;101101110 ('?', 3114)&lt;br /&gt;1011011110 ('j', 1449)&lt;br /&gt;1011011111 ('Y', 1415)&lt;br /&gt;10111 ('u', 45643)&lt;br /&gt;1100 ('h', 94800)&lt;br /&gt;1101 ('i', 92948)&lt;br /&gt;111 ('e', 177161)&lt;br /&gt;data can be compressed from 15873136 bits into 9016123 bits (0.568011%)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7283436824467007296?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7283436824467007296/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7283436824467007296' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7283436824467007296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7283436824467007296'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2010/03/python.html' title='pythonでハフマン符号化'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3783416783678690888</id><published>2009-07-30T15:05:00.006+09:00</published><updated>2009-07-31T22:12:57.929+09:00</updated><title type='text'>pythonで加重ランダム</title><content type='html'>何かをランダムに出現させたいが、値によって出現率が異なるようにしたい。&lt;br /&gt;&lt;br /&gt;bisectモジュールをうまくつかうといいみたい。見つけた元ネタ：&lt;br /&gt;&lt;a href="http://code.activestate.com/recipes/576370/"&gt;http://code.activestate.com/recipes/576370/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;bisectは、ソート済みのリストについて頭出しができるモジュール。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(いろいろテスト)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import bisect&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; scale = [10, 20, 30, 40, 50]   # ソート済みのリストを使うこと&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; bisect.bisect(scale, 15)    # 15はどこに位置する?&lt;br /&gt;1&lt;br /&gt;(これはスライス範囲を指定するときの場所。つまり10と20の間ってこと)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; bisect.bisect(scale, 46)    # 46は?&lt;br /&gt;4&lt;br /&gt;(この場合は、40と50の間ってこと)&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; scale = ['a', 'j', 'z']  # 数字以外でも使えるのかな&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; bisect.bisect(scale, 'q')&lt;br /&gt;2&lt;br /&gt;(できそうですね)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;元ネタのコードには何も付け加える余地がないからここでは動作原理のみ書くと、間の空き具合がまちまちな数のリストを準備しておいて、それに乱数を使ってbisect探索するということ。random関数が0.0から1.0の乱数を出すから、値の範囲も0.0から1.0で作ると相性がよい。&lt;br /&gt;&lt;br /&gt;下のようなスケールがあるとして、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0.0   0.1           0.3                            1.0&lt;br /&gt; |-----+-------------+------------------------------|&lt;br /&gt;  範囲A     範囲B                  範囲C&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;で、ランダム値にこのスケールをあてはめれば、範囲Cが選ばれる確率は70%くらいで、範囲Aは大体10%くらいしか出現しないことになる。&lt;br /&gt;&lt;br /&gt;実証したコード：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import bisect&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import random&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; scale, items = [0.1, 0.3, 1.0], ['A', 'B', 'C']&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; [items[bisect.bisect(scale, random.random())] for i in xrange(100)]&lt;br /&gt;['C', 'C', 'C', 'A', 'B', 'C', 'A', 'A', 'C', 'C', 'C', 'C', 'C', 'B', 'C', 'B',&lt;br /&gt; 'B', 'C', 'C', 'C', 'A', 'C', 'C', 'C', 'C', 'C', 'C', 'B', 'C', 'B', 'C', 'B',&lt;br /&gt; 'B', 'C', 'C', 'C', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',&lt;br /&gt; 'B', 'C', 'B', 'C', 'A', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'A', 'B',&lt;br /&gt; 'B', 'C', 'C', 'B', 'C', 'A', 'C', 'A', 'C', 'B', 'C', 'C', 'C', 'C', 'C', 'B',&lt;br /&gt; 'C', 'C', 'C', 'A', 'C', 'C', 'C', 'B', 'C', 'B', 'C', 'A', 'B', 'A', 'B', 'C',&lt;br /&gt; 'B', 'C', 'C', 'C']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cの出現率が多くて、Aがレア。なるほどねー&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3783416783678690888?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3783416783678690888/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3783416783678690888' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3783416783678690888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3783416783678690888'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/07/python.html' title='pythonで加重ランダム'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8178535120829695512</id><published>2009-06-16T13:27:00.004+09:00</published><updated>2009-06-16T13:30:14.187+09:00</updated><title type='text'>pythonでタートルグラフィック</title><content type='html'>Tkinterモジュールのオマケ?にタートルグラフィックのライブラリがあって、多分一番手っ取り早くCGっぽいことを始められる。&lt;br /&gt;&lt;br /&gt;下のスクリプトを適当なファイル名で保存してから実行すると、ペンでグリグリ落書きしているかのようなデモが走る。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from turtle import *&lt;br /&gt;import random&lt;br /&gt;&lt;br /&gt;speed('fast')&lt;br /&gt;&lt;br /&gt;while True:&lt;br /&gt;  for i in xrange(1000):&lt;br /&gt;     down()&lt;br /&gt;     forward(3)&lt;br /&gt;     up()&lt;br /&gt;     forward(2)&lt;br /&gt;     right(random.randint(-3,10))&lt;br /&gt;  reset()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;また、コンソールから、&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; import turtle&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; turtle.demo()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;とか&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; import turtle&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; turtle.demo2()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;とかすると、出来あいのデモが見られたりする。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8178535120829695512?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8178535120829695512/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8178535120829695512' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8178535120829695512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8178535120829695512'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/06/python.html' title='pythonでタートルグラフィック'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-193782193674052093</id><published>2009-06-01T14:14:00.005+09:00</published><updated>2009-06-01T15:44:05.864+09:00</updated><title type='text'>MS-Accessでリンクテーブルを張替え(VBA)</title><content type='html'>pythonで書きたくても、VBAなんかを書かなくちゃいけないときもある。一応成果メモ。&lt;br /&gt;&lt;br /&gt;MS-Accessで、データ自体はどこかの共有フォルダ内のmdbファイルに置いておいて、それを各クライアントがリンクテーブルとして使う、という運用はよくあるパターン。&lt;br /&gt;&lt;br /&gt;で、クライアントを新しく配置するごとに、リンクテーブルをちまちま張りなおすのは面倒だなあ、ということで、モジュール化した。refresh_link_tables というサブルーチンを呼ぶと、ネットワークフォルダにドライブ名を振って、リンクテーブルの定義を消して、あたらしくリンクを作り直している。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Function exists_table(ByVal name As String)&lt;br /&gt;    On Error Resume Next&lt;br /&gt;    exists_table = CurrentDb.TableDefs(name).name = name&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Sub connect_net_drive()&lt;br /&gt;    Dim oShell As Object&lt;br /&gt;    Set oShell = CreateObject("WScript.Shell")&lt;br /&gt;    '環境にあわせて適宜変える。最後のTrueは同期実行のしるし&lt;br /&gt;    oShell.Run "NET USE Q: \\some_server\shared_folder passwd1 /USER:user1", , True&lt;br /&gt;    Set oShell = Nothing&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Public Sub refresh_link_tables()&lt;br /&gt;    Call connect_net_drive&lt;br /&gt;    tt = Array("master", "master2", "journal1", ...... )  'リンクするテーブルをいくつでも&lt;br /&gt;    For Each table_name In tt&lt;br /&gt;        If exists_table(table_name) Then&lt;br /&gt;            CurrentDb.TableDefs.Delete (table_name)&lt;br /&gt;        End If&lt;br /&gt;        Set tdef = CurrentDb.CreateTableDef(table_name)&lt;br /&gt;        tdef.Connect = ";database=Q:\sample\shared_db.mdb"  '環境にあわせて書き換え&lt;br /&gt;        tdef.SourceTableName = table_name&lt;br /&gt;        CurrentDb.TableDefs.Append (tdef)&lt;br /&gt;    Next&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;補足：WScript.Shell オブジェクトを作ってNTコマンドを外部で実行するというのがなんだか格好悪いと思うなら、WScript.Network オブジェクトの MapNetworkDrive メソッドを使っても似たことができる。まあ、やりたいことが実現するのならなんでもいいや。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-193782193674052093?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/193782193674052093/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=193782193674052093' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/193782193674052093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/193782193674052093'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/06/ms-accessvba.html' title='MS-Accessでリンクテーブルを張替え(VBA)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-4858505120310236864</id><published>2009-05-20T15:52:00.000+09:00</published><updated>2009-05-20T15:54:04.483+09:00</updated><title type='text'>pythonでキャッシュサーバーを叩く</title><content type='html'>WebサーバーにExcelシートなんかを置いて、ダウンロードさせる場合があるとする。ダウンロード経路にsquidとかのキャッシュサーバーがある場合、こいつが旧バージョンのドキュメントをしばらく確保して、なかなか新バージョンが配布できない。HTMLファイルなどだったら[F5]キーで明示的にキャッシュを再取得すればいいんだけど、Excelじゃできない。&lt;br /&gt;&lt;br /&gt;キャッシュを回避するためにファイル名を明示的に変えて置いておくという方法があるにはあるが、なんだかムキになってキャッシュ破棄にこだわりたくなった。つまり Pragma:no-cache とかそんなヘッダを投げつければいいんでしょ。結果、下のようなスクリプトを書いた。Tkinter版。print文でデバッグ情報を出力するので、標準出力をどっかに表示できること。&lt;br /&gt;&lt;br /&gt;スクリプト中の cache_server 変数には、あらかじめ自分の環境のプロキシサーバーとポート番号を設定する。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- coding: cp932 -*-&lt;br /&gt;&lt;br /&gt;import Tkinter as tk&lt;br /&gt;import httplib, urllib&lt;br /&gt;&lt;br /&gt;cache_server = "192.168.1.100:3128"  #configure yourself&lt;br /&gt;&lt;br /&gt;def clear_cache(url):&lt;br /&gt;    print url&lt;br /&gt;    headers = {"Pragma": "no-cache", }&lt;br /&gt;    conn = httplib.HTTPConnection(cache_server)&lt;br /&gt;    conn.request("GET", url, "", headers)&lt;br /&gt;    response = conn.getresponse()&lt;br /&gt;    print response.status, response.reason&lt;br /&gt;    print response.getheaders()&lt;br /&gt;    conn.close()&lt;br /&gt;    return "%s %s" % (response.status, response.reason)&lt;br /&gt;&lt;br /&gt;class CacheRefresherFrame(tk.Frame):&lt;br /&gt;&lt;br /&gt;    def __init__(self, parent, **kwag):&lt;br /&gt;        tk.Frame.__init__(self, parent, **kwag)&lt;br /&gt;        self.s1 = tk.StringVar()&lt;br /&gt;        self.s2 = tk.StringVar()&lt;br /&gt;        self.t1 = tk.Entry(self, width=100, textvariable=self.s2)&lt;br /&gt;        self.b1 = tk.Button(self, text='refresh cash', command=self.do_hello)&lt;br /&gt;        self.l1 = tk.Label(self, textvariable=self.s1)&lt;br /&gt;        self.t1.pack()&lt;br /&gt;        self.b1.pack()&lt;br /&gt;        self.l1.pack()&lt;br /&gt;        self.s1.set('ready')&lt;br /&gt;        self.t1.focus()&lt;br /&gt;&lt;br /&gt;    def do_hello(self):&lt;br /&gt;        self.t1.configure(state=tk.DISABLED)&lt;br /&gt;        self.b1.configure(state=tk.DISABLED)&lt;br /&gt;        url = self.s2.get()&lt;br /&gt;        self.s1.set('processing %s ...' % url)&lt;br /&gt;        self.update()&lt;br /&gt;        try:&lt;br /&gt;            self.s1.set(clear_cache(url))&lt;br /&gt;        finally:&lt;br /&gt;            self.t1.configure(state=tk.NORMAL)&lt;br /&gt;            self.b1.configure(state=tk.NORMAL)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;root = tk.Tk()&lt;br /&gt;root.title(u'キャッシュサーバーにキャッシュ破棄を指示するスクリプト')&lt;br /&gt;CacheRefresherFrame(root).pack()&lt;br /&gt;root.mainloop()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ここまで書いてから、ファイル名を変えずに明示的にキャッシュを回避する方法を思いついてしまった。ダウンロードページのHTMLで、ハテナ記号つきのリンクを張ればよかったんだよね。たとえば、app.xls というシートを配布するときに、リンクのURLに app.xls?ver_2 とか書くってこと。&lt;br /&gt;&lt;br /&gt;あと、メソッド名が do_hello とかになっている理由は、公開用に名称を整理するのが面倒だったから。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-4858505120310236864?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/4858505120310236864/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=4858505120310236864' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4858505120310236864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4858505120310236864'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/05/python.html' title='pythonでキャッシュサーバーを叩く'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1487820685741689267</id><published>2009-05-11T13:25:00.003+09:00</published><updated>2009-05-11T13:35:43.649+09:00</updated><title type='text'>pythonでsplit</title><content type='html'>文字列を一定のルールでちょん切って配列にするという仕事はよく生じる。&lt;br /&gt;こんなときは、文字列にsplitメソッドを適用すればよい。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; "out of google, out of existence".split(" ")&lt;br /&gt;['out', 'of', 'google,', 'out', 'of', 'existence']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;でもsplitメソッドは、不定数の空白文字で区切られたものをうまく扱えない。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; "out    of google, out of   existence".split(" ")&lt;br /&gt;['out', '', '', '', 'of', 'google,', 'out', 'of', '', '', 'existence']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;perlだと正規表現を使ってsplitもできたのになあ、と不便に思って調べると、ちゃんとpythonでもそれができた。ただ、明示的に正規表現オブジェクトのメソッドとしてこれを使う。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import re&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; r1 = re.compile("\s+")&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; r1.split("out    of google, out of   existence")&lt;br /&gt;['out', 'of', 'google,', 'out', 'of', 'existence']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;あらよかったね。&lt;br /&gt;&lt;br /&gt;あと、例文には何の意味もありません。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1487820685741689267?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1487820685741689267/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1487820685741689267' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1487820685741689267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1487820685741689267'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/05/pythonsplit.html' title='pythonでsplit'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1769823639292460580</id><published>2009-04-08T13:41:00.007+09:00</published><updated>2009-04-08T13:56:15.538+09:00</updated><title type='text'>pythonで再帰関数</title><content type='html'>メールの同報エイリアスのリスト中に、さらに別の同報エイリアスが入れ子になっているときがある。再帰的な展開ルーチンを書くことで、一発で最後まで展開することができる。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;aliases = {&lt;br /&gt;  'haken':    ['Michael', ],&lt;br /&gt;  'kaikei':   ['Tanaka', 'Yamada', 'Ogawa', 'haken', ],&lt;br /&gt;  'syomu':    ['Kobayashi', 'Shima', ],&lt;br /&gt;  'syomu_ex': ['syomu', 'Futamura', ],&lt;br /&gt;  'all':      ['kaikei', 'syomu_ex', 'BigBoss', ],&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# recursive!&lt;br /&gt;def expand_alias(k):&lt;br /&gt;  for i in aliases[k]:&lt;br /&gt;    if aliases.has_key(i):&lt;br /&gt;      for i2 in expand_alias(i):&lt;br /&gt;        yield i2&lt;br /&gt;    else:&lt;br /&gt;      yield i&lt;br /&gt;&lt;br /&gt;for i in aliases.keys():&lt;br /&gt;  print "%s: %s" % (i, ", ".join([j for j in expand_alias(i)]))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;実行結果（各行の表示順は異なるかもしれない）&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;kaikei: Tanaka, Yamada, Ogawa, Michael&lt;br /&gt;syomu: Kobayashi, Shima&lt;br /&gt;all: Tanaka, Yamada, Ogawa, Michael, Kobayashi, Shima, Futamura, BigBoss&lt;br /&gt;haken: Michael&lt;br /&gt;syomu_ex: Kobayashi, Shima, Futamura&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;再帰的な処理がyieldで値を返すようにして、これを利用するほうはfor文なんかで簡単に扱えるようにしてしまうのが快適（この例ではforじゃなくてリスト内包で利用しているが）。yieldは便利だなあ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1769823639292460580?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1769823639292460580/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1769823639292460580' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1769823639292460580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1769823639292460580'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/04/python.html' title='pythonで再帰関数'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3828545743694292496</id><published>2009-03-17T22:34:00.005+09:00</published><updated>2009-03-18T00:57:22.493+09:00</updated><title type='text'>Whoosh</title><content type='html'>pure pythonな全文検索ライブラリ。luceneを意識しているようだ。&lt;br /&gt;http://trac.whoosh.ca/&lt;br /&gt;&lt;br /&gt;かなり新しいプロジェクトみたいなので、うまくいってほしい。&lt;br /&gt;アナライザとかn-gramとかいう単語もページ中にちらほら見かけるので、きっとCJK系も&lt;br /&gt;扱える。サイト内にも、完全unicode対応とあった。&lt;br /&gt;&lt;br /&gt;とりあえずトップページから「Whooshの特徴」とでもいった部分を抜き出して訳しておく。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Some of Whoosh's features include:&lt;br /&gt;Whooshはこんな特徴とかがあるよ：&lt;br /&gt;&lt;br /&gt; * Pythonic API.&lt;br /&gt;   python風なAPI&lt;br /&gt; * Pure-Python. No compilation or binary packages needed, no mysterious crashes.&lt;br /&gt;   ピュアpython。別途コンパイルが必要なものはない。だから謎のクラッシュも起こらない&lt;br /&gt; * Fielded indexing and search.&lt;br /&gt;   フィールドに分けた索引検索ができる&lt;br /&gt; * Fast indexing and retrieval -- much faster than any other pure-Python solution.&lt;br /&gt;   高速な索引生成と検索。ピュアpythonなものの中ではダントツ早い&lt;br /&gt;   (C/C++製のものにはさすがに負けるけど)&lt;br /&gt; * Pluggable scoring algorithm (including BM25F), text analysis, storage,&lt;br /&gt;   posting format, etc.&lt;br /&gt;   適合度のアルゴリズム、アナライズ、格納、ポストするフォーマット等がプラグインで&lt;br /&gt;   入れ替え可能&lt;br /&gt; * Powerful query language parsed by pyparsing.&lt;br /&gt;   検索式が強力。pyparsingを使える&lt;br /&gt; * Pure Python spell-checker (as far as I know, the only one). &lt;br /&gt;   ピュアpythonなスペルチェッカー。たぶんWhooshが唯一&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;pyLuceneとかが結局java必要だったりして悶々としていたので、これは注目しておこう。っていうか、近くちゃんといじってみよう&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3828545743694292496?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3828545743694292496/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3828545743694292496' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3828545743694292496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3828545743694292496'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/whoosh.html' title='Whoosh'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-357275036376791037</id><published>2009-03-09T10:01:00.003+09:00</published><updated>2009-05-19T15:14:03.263+09:00</updated><title type='text'>WebOb</title><content type='html'>[TODO]:WebObで検索すると妙に検索順位が高いらしい。せっかくなのでもう少し詳しく書き直す&lt;br /&gt;&lt;br /&gt;WSGIアプリを書くときに色々楽できるようになるライブラリ。他のフレームワークにすでに組み込まれていることもあるが、WebObだけ単独で使ってもよい。python付属のcgiライブラリやcookieライブラリを使いやすくしてくれるラッパーに過ぎないが、つまらないミスを防いでシンプルに書けるようになるのがいい。これは標準配布になってもいいと思うなあ。&lt;br /&gt;&lt;br /&gt;Requestオブジェクトを使うと、パラメータやcookieの入力がまとめてここから扱える。&lt;br /&gt;準備は、WSGIアプリが受け取る辞書オブジェクト(仮引数はenvironが多い)を突っ込んでRequestを生成するのみ。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;req = webob.Requset(environ)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;あとは、req.paramsにGETやPOST経由で届いたパラメータが辞書になって入っていたり、req.cookiesにCOOKIEの値が同じく辞書になって入っていたりするので、単に参照すればよい。&lt;br /&gt;&lt;br /&gt;Responseオブジェクトは、WSGIアプリとして生成される。使い方は、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def some_app(environ, start_response):&lt;br /&gt;    ...&lt;br /&gt;    res = webob.Response()&lt;br /&gt;    res.body = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;hello&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;    return res(environ, start_response)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;といった感じ。MIMEメッセージ設定（初期値はtext/html)やCOOKIEの設定も、resインスタンスのメソッドとしてひととおり準備されている。&lt;br /&gt;&lt;br /&gt;HTTPでのリダイレクトは、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;res = webob.exc.HTTPSeeOther(location="dokosoko.html")&lt;br /&gt;return res(environ, start_response)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;みたいに行う。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-357275036376791037?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/357275036376791037/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=357275036376791037' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/357275036376791037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/357275036376791037'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/webob.html' title='WebOb'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3198140985174434545</id><published>2009-03-08T21:35:00.002+09:00</published><updated>2009-03-08T21:49:53.865+09:00</updated><title type='text'>本メモ・本を読む本</title><content type='html'>『本を読む本』アドラー&amp;ドーレン著、講談社学術文庫。ブックオフに安値で転がっていた。&lt;br /&gt;&lt;br /&gt;本の読み方についての方法論。ヒマつぶしみたいな本ばかり持ってきて字面だけを追っかけて、それを読書だと思い込んでると損するよ、という話。読書の深さにはそれぞれレベルがあるから、適当な品質の本は浅いレベルの読み方で読み飛ばしちゃって、本当に価値がある本を見つけたらそいつは一生かかっても徹底的に読みつくしなさい、それこそ読書だよ、とのこと。いやあハンパな本読みですんません。この本はちゃんと本棚に納めて、背表紙だけはいつも見えるようにしておこう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3198140985174434545?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3198140985174434545/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3198140985174434545' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3198140985174434545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3198140985174434545'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/blog-post_08.html' title='本メモ・本を読む本'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-2471357260107599536</id><published>2009-03-07T21:31:00.003+09:00</published><updated>2009-03-07T22:03:59.034+09:00</updated><title type='text'>読書メモ（カラシニコフ・ベルカ、吠えないのか？）</title><content type='html'>『カラシニコフ(1)(2)』松本仁一著、朝日文庫　を読んだ。自動小銃の傑作であるカラシニコフが作られた時の話（本人へのインタビュー含む）から、それがあまりに性能がよく扱いやすいために、貧困国の住民がそれを使うことが可能になってしまったという話までを取材した本。そこにはアジアやアフリカの天然資源の利権がイヤな感じに絡んでいたり、植民地支配や冷戦のために煽られた対立がこじれてしまった姿が浮かんだり、しまいには子供ゲリラが弾除け代わりに戦場に駆り出されていく話になっていったりして、読んでひたすら暗くなる。書きぶりは淡々としていて、どんな文にもよけいな修飾はない。もちろん、書くべき事実が凄まじすぎるのでヘタに飾る必要が最初からない。&lt;br /&gt;&lt;br /&gt;この本で、『ベルカ、吠えないのか？』古川日出男、文春文庫　をちょっと思い出した。カラシニコフが「世界に銃が拡散していく話」なら、こっちは「世界に犬が拡散していく話」。多分ちゃんと歴史を踏まえているんだし、世界一周的な場面の移り変わりも面白かったけど、文体がなんかハードボイルドのなりそびれって感じがしてそこは好きじゃない。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-2471357260107599536?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/2471357260107599536/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=2471357260107599536' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2471357260107599536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2471357260107599536'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/blog-post.html' title='読書メモ（カラシニコフ・ベルカ、吠えないのか？）'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3936900691658328599</id><published>2009-03-06T01:08:00.002+09:00</published><updated>2009-03-06T01:16:47.254+09:00</updated><title type='text'>OpenID自習</title><content type='html'>OpenIDの勉強をちょっとしてみようかなと思った。&lt;br /&gt;http://openid.net/specs/openid-authentication-1_1.html を見ながら、例え話みたいなもので理解してみようと考えた。例えが的確かはわからない。&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;&lt;br /&gt;アマヤ君が、目の前にあるなんちゃらランドに入場したいと思っている。このなんちゃらランドの入場管理役は、入場したい人が本当にその人本人であることが証明できたら入場を許可してもよいと思っている。&lt;br /&gt;&lt;br /&gt;ここでいう「本人であることの証明」とは、本人の所属する組織がその人を確かに本人だと認めることである。&lt;br /&gt;&lt;br /&gt;なので入場管理役は、まずアマヤ君という名前の人物がどこに所属しているかを調べる。これをアマヤ君本人に聞いては信用ならないので、事務室に帰って専用の検索サービスで調べる。ここで、アマヤ君はタチバナ市に所属する人物であることがわかった。&lt;br /&gt;&lt;br /&gt;入場管理役「アマヤ君とやら、あなたがあなたであることを証明できるのはタチバナ市の認証担当者ということだ。たいへんお手数だが、今からタチバナ市に赴いて、その担当者からこの書類にハンコをもらってきてくれたまえ。押してもらうハンコは、必ず40227番のハンコと指定しなさい。タチバナ市にはたくさんのハンコがあるはずだが、これ以外のハンコが押されている場合は無効であるから心せよ。」&lt;br /&gt;&lt;br /&gt;今、入場管理役がハンコの番号をはっきり指定したのは、現在、その管理役自身も手元にその40227番のハンコと全く同じものを持っているからである。実はさっき、アマヤ君が訪れてから、大急ぎでタチバナ市に渡りをつけてこのハンコを共有したのだ。（次回からは、他のタチバナ市の人間が来ても、しばらくこのハンコを使いまわす予定。タチバナ市でなくハイジマ町だったりしたらまた別のハンコを準備する）&lt;br /&gt;&lt;br /&gt;数時間後、アマヤ君が息を喘がせて再びなんちゃらランドの門前に帰ってきた。タチバナ市の担当者にハンコをもらってきたという。&lt;br /&gt;&lt;br /&gt;よろしい、精査するので待ちたまえ、と、入場管理役はその書類を持って事務室に戻る。そこで、同じ文面の書類を作って、自分が持っている40227番のハンコを使って全く同じようにその書類の上に捺印してみた。完全に同じハンコを使うから、文字のインクとにじんで朱肉が交じりあう様子も全く同じだ。これはもう疑いなく、アマヤ君がタチバナ市の担当者に認められて戻ってきたということに違いない。&lt;br /&gt;&lt;br /&gt;大変おまたせした、アマヤ君、我々は君を確かにアマヤ君であると認め、このなんちゃらランドへの入園を心から歓迎するものである。&lt;br /&gt;&lt;br /&gt;※なんちゃらランドとタチバナ市が行った印章の共有は、OpenID1.1では平文方式とDH鍵交換方式があってどちらかを選べる。平文が実装は楽だろうが、セキュリティに劣る。&lt;br /&gt;&lt;br /&gt;※このケースでは、なんちゃらランドが印章をあらかじめ共有しているという「スマートモード」の場合を想定した。印章をあらかじめ共有しない「ダムモード」というやりかたもある。&lt;br /&gt;&lt;br /&gt;※アマヤ君がタチバナ市に行かされたのは、checkid_immediateモードでか、checkid_setupモードでかは明確にしていない。仕様では、どっちも似たようなものと読めた。&lt;br /&gt;&lt;br /&gt;※アマヤ君がどうやってタチバナ市に自分のことを証明したかは、なんちゃらランドでは関知していない。合言葉でも使ったんじゃないの？または顔パスなのかな。どっちでもいいよ。ハンコさえ押してもらったんなら。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3936900691658328599?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3936900691658328599/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3936900691658328599' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3936900691658328599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3936900691658328599'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/openid.html' title='OpenID自習'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-4219356722052906318</id><published>2009-03-04T21:43:00.004+09:00</published><updated>2009-03-04T21:48:59.736+09:00</updated><title type='text'>pythonでCDをイジェクト</title><content type='html'>どうも手持ちのPCのCDがイジェクトしにくい。何十回も試してはじめてトレイが出てくるという具合。&lt;br /&gt;&lt;br /&gt;下のようなコードを実行して、何回もイジェクトを試行するのを自動化した。要pygame。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import pygame&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; pygame.cdrom.init()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; cd_obj = pygame.cdrom.CD(0)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; cd_obj.init()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; cd_obj.eject()  #一回だけイジェクト試して…&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; while 1: cd_obj.eject()  #うまくいくまでずっとやってて&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ctypeモジュールを使って直接win32APIを叩くなんていうのもあるんだろうけど、考えるのめんどい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-4219356722052906318?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/4219356722052906318/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=4219356722052906318' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4219356722052906318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4219356722052906318'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/pythoncd.html' title='pythonでCDをイジェクト'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-9151205650372705846</id><published>2009-03-03T23:27:00.002+09:00</published><updated>2009-03-03T23:35:34.079+09:00</updated><title type='text'>python challenge 面白い</title><content type='html'>http://www.pythonchallenge.com/ がかなり面白く、悩みながらちょっとづつ進めている。現在10番。&lt;br /&gt;&lt;br /&gt;仕掛けとしては、問題のページにあるヒントを手がかりに、次のページのURLを当てるというもの。それをブラウザのアドレス欄に直接入力してみて、当たっていれば次の問題が表示される。&lt;br /&gt;python challengeというだけあって、pythonを使うと問題が解きやすいように作ってある。事実、python抜きではかなり分かりにくい場合もある。&lt;br /&gt;&lt;br /&gt;これは自習教材を作るときに使える方法だなと思う。ある練習問題を正しく解くと次の問題に進めるから、達成感がある。&lt;br /&gt;pythonの初歩の学習にはpython challengeをマネした教材を用意して、上級になったらpython challengeそのものをやればいいか。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-9151205650372705846?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/9151205650372705846/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=9151205650372705846' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/9151205650372705846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/9151205650372705846'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/python-challenge.html' title='python challenge 面白い'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5502767958783869506</id><published>2009-03-03T16:47:00.004+09:00</published><updated>2009-03-03T16:57:14.725+09:00</updated><title type='text'>URLメモ・アーカイブ公開システム</title><content type='html'>個人アーカイブのようなものを作る仕組みを実装してみた。&lt;br /&gt;&lt;a href="http://giraffe.topaz.ne.jp/wiki/doku.php/tinyrep"&gt;http://giraffe.topaz.ne.jp/wiki/doku.php/tinyrep&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;WSGIアプリとして書いたが、CGIとして動作する。python製（なんか、perlとかphpが書けなくなってきた）。&lt;br /&gt;&lt;br /&gt;使用法などのドキュメントはそのうち整備がいるが、難しいものではない。wikiに添付ファイルをくっつけたようなもの。&lt;br /&gt;ただ、タイトルとタグのデータを登録と同時にdelicious（ソーシャルブックマークのひとつ）にも送信する仕組みを内部的に組み込んだので、階層管理や簡単な検索までならそちらに任せてしまうことができる。と思う。&lt;br /&gt;ソーシャルブックマークなんだから、誰かが気に入った記事はブックマーク数が増えてタグが充実していくかもしれない。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5502767958783869506?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5502767958783869506/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5502767958783869506' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5502767958783869506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5502767958783869506'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/03/url.html' title='URLメモ・アーカイブ公開システム'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8789678787455856865</id><published>2009-01-07T09:50:00.002+09:00</published><updated>2009-01-07T09:58:51.325+09:00</updated><title type='text'>pythonでCAS</title><content type='html'>CASサーバとクライアントアプリのサンプルを書く。&lt;br /&gt;&lt;br /&gt;サーバーのコード(casserver.py)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- encoding: cp932 -*-&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;極めて簡易なCASサーバー実装。2.0プロトコルのつもり。&lt;br /&gt;&lt;br /&gt;使用法：スクリプトをダブルクリックでサーバープロセスが開始する。&lt;br /&gt;&lt;br /&gt;・https:// でなく http:// で動く（多分仕様違反だが）&lt;br /&gt;・すべてのログインIDを、入力したパスワードを評価せずに認証する&lt;br /&gt;・service値のチェックを省略している&lt;br /&gt;・シングルサインオンには未対応(Cookieを交換しないので)&lt;br /&gt;・その他、最初のログインに関わる機能以外をたくさん省略&lt;br /&gt;"""&lt;br /&gt;import cgi, random&lt;br /&gt;&lt;br /&gt;def get_cgi_params(environ):&lt;br /&gt;    pars = cgi.parse(environ['wsgi.input'], environ=environ, keep_blank_values=True)&lt;br /&gt;    for k in pars: pars[k] = "".join(pars[k])&lt;br /&gt;    return pars&lt;br /&gt;&lt;br /&gt;ticketstore = dict()&lt;br /&gt;ticketseed = '012456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'&lt;br /&gt;&lt;br /&gt;def app_cas_login(environ,start_response):&lt;br /&gt;    pars = get_cgi_params(environ)&lt;br /&gt;    service = pars.get("service", "")&lt;br /&gt;    userid = pars.get("userid", "")&lt;br /&gt;    if userid:&lt;br /&gt;        ticket = 'ST-' + ''.join([random.choice(ticketseed) for i in xrange(32)])&lt;br /&gt;        ticketstore[ticket] = (userid, service)&lt;br /&gt;        print 'ticket:', ticket, userid, service&lt;br /&gt;        location = "%s?ticket=%s" % (service, ticket,)&lt;br /&gt;        print "redirect:", location&lt;br /&gt;        start_response("302 Moved Temporarily", [('Location', location)])&lt;br /&gt;        return []&lt;br /&gt;    start_response("200 OK", [('Content-Type','text/html')])&lt;br /&gt;    return ["""&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;LOGIN&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;form action="login" method="post"&amp;gt;&lt;br /&gt;&amp;lt;input type="hidden" name="service" value="%s"&amp;gt;&lt;br /&gt;ID:&amp;lt;input name="userid"&amp;gt;&amp;lt;br&amp;gt;PASS:&amp;lt;input name="pass"&amp;gt;&amp;lt;br&amp;gt;&amp;lt;input type="submit"&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;""" % (service,), '']&lt;br /&gt;&lt;br /&gt;def app_cas_validate(environ,start_response):&lt;br /&gt;    pars = get_cgi_params(environ)&lt;br /&gt;    service = pars.get("service", "")&lt;br /&gt;    ticket = pars.get("ticket", "")&lt;br /&gt;    try:&lt;br /&gt;      userid = ticketstore[ticket][0]&lt;br /&gt;      ticketstore.pop(ticket)&lt;br /&gt;      start_response("200 OK", [('Content-Type','text/xml')])&lt;br /&gt;      return ["""&amp;lt;cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'&amp;gt;&lt;br /&gt;  &amp;lt;cas:authenticationSuccess&amp;gt;&lt;br /&gt;    &amp;lt;cas:user&amp;gt;%s&amp;lt;/cas:user&amp;gt;&lt;br /&gt;    &amp;lt;cas:ticket&amp;gt;%s&amp;lt;/cas:ticket&amp;gt;&lt;br /&gt;    &amp;lt;/cas:Attributes&amp;gt;&lt;br /&gt;  &amp;lt;/cas:authenticationSuccess&amp;gt;&lt;br /&gt;&amp;lt;/cas:serviceResponse&amp;gt;""" % (userid, ticket, ), '']&lt;br /&gt;    except KeyError:&lt;br /&gt;      start_response("200 OK", [('Content-Type','text/xml')])&lt;br /&gt;      return ["""&amp;lt;cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'&amp;gt;&lt;br /&gt;  &amp;lt;cas:authenticationFailure code='INVALID_TICKET'&amp;gt;&lt;br /&gt;    ticket '%s' is expired or not recognized&lt;br /&gt;  &amp;lt;/cas:authenticationFailure&amp;gt;&lt;br /&gt;&amp;lt;/cas:serviceResponse&amp;gt;""" % (ticket,), '']&lt;br /&gt;&lt;br /&gt;dispatch_table = {&lt;br /&gt;    'login':          app_cas_login,&lt;br /&gt;    'serviceValidate':app_cas_validate,&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def app_dispatcher(environ, start_response):&lt;br /&gt;    """ URL情報から実行するWSGIを決めるミニミドルウェア """&lt;br /&gt;    if environ.has_key('PATH_INFO'):&lt;br /&gt;        a = environ['PATH_INFO'].split("/")[-1]&lt;br /&gt;    else:&lt;br /&gt;        a = environ['SCRIPT_NAME'].split("/")[-1]&lt;br /&gt;    a = a.split(".")[0]&lt;br /&gt;    app = dispatch_table.get(a)&lt;br /&gt;    return app(environ, start_response)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    from wsgiref.simple_server import make_server&lt;br /&gt;    srv = make_server('localhost', 8081, app_dispatcher)&lt;br /&gt;    srv.serve_forever()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;クライアントアプリのコード(client.py)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- encoding: cp932 -*-&lt;br /&gt;import urllib&lt;br /&gt;&lt;br /&gt;# 自分自身のログインURL(service引数)&lt;br /&gt;url_mylogin = "http://localhost:8082/mylogin"&lt;br /&gt;# CASサーバーの認証画面&lt;br /&gt;url_caslogin = "http://localhost:8081/login"&lt;br /&gt;# CASサーバーのticket問い合わせ用ベースURL&lt;br /&gt;url_casvalidate = "http://localhost:8081/serviceValidate"&lt;br /&gt;&lt;br /&gt;def get_cgi_params(environ):&lt;br /&gt;    import cgi&lt;br /&gt;    pars = cgi.parse(environ['wsgi.input'], environ=environ, keep_blank_values=True)&lt;br /&gt;    for k in pars: pars[k] = "".join(pars[k])&lt;br /&gt;    return pars&lt;br /&gt;&lt;br /&gt;def my_login_test(environ,start_response):&lt;br /&gt;    """クライアントアプリ側の動作テスト"""&lt;br /&gt;    pars = get_cgi_params(environ)&lt;br /&gt;    ticket = pars.get("ticket", "")&lt;br /&gt;    # ticket引数がなければ、CASサーバーの認証画面にリダイレクトする&lt;br /&gt;    if not ticket:&lt;br /&gt;        url = "%s?service=%s" % (url_caslogin, urllib.quote(url_mylogin))&lt;br /&gt;        print "redirect:", url&lt;br /&gt;        start_response("302 Moved Temporarily", [('Location', url)])&lt;br /&gt;        return []&lt;br /&gt;    # 受け取ったticket引数を使って、CASのヴァリデーションをする。&lt;br /&gt;    import re&lt;br /&gt;    url = "%s?ticket=%s&amp;service=%s" % (url_casvalidate, ticket, urllib.quote(url_mylogin))&lt;br /&gt;    print "validate:", url&lt;br /&gt;    # レスポンスを文字列に格納して、中身を調べる&lt;br /&gt;    r = urllib.urlopen(url).read()&lt;br /&gt;    # ここでは簡易に行うためにXMLのパースでなく正規表現による抽出で済ます&lt;br /&gt;    r1 = re.compile("&amp;lt;cas:user&amp;gt;(.+?)&amp;lt;/cas:user&amp;gt;")&lt;br /&gt;    r2 = r1.findall(r)&lt;br /&gt;    if len(r2) &amp;gt; 0:&lt;br /&gt;      userid = r2[0]&lt;br /&gt;      start_response("200 OK", [('Content-Type','text/plain')])&lt;br /&gt;      return ['hello,', userid, '']&lt;br /&gt;    else:&lt;br /&gt;      start_response("200 OK", [('Content-Type','text/plain')])&lt;br /&gt;      return ['something wrong', '']&lt;br /&gt;&lt;br /&gt;dispatch_table = {&lt;br /&gt;    'mylogin':   my_login_test,&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def app_dispatcher(environ, start_response):&lt;br /&gt;    """ URL情報から実行するWSGIを決めるミニミドルウェア """&lt;br /&gt;    if environ.has_key('PATH_INFO'):&lt;br /&gt;        a = environ['PATH_INFO'].split("/")[-1]&lt;br /&gt;    else:&lt;br /&gt;        a = environ['SCRIPT_NAME'].split("/")[-1]&lt;br /&gt;    a = a.split(".")[0]&lt;br /&gt;    app = dispatch_table.get(a)&lt;br /&gt;    return app(environ, start_response)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    from wsgiref.simple_server import make_server&lt;br /&gt;    srv = make_server('localhost', 8082, app_dispatcher)&lt;br /&gt;    srv.serve_forever()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ふたつのスクリプトをそれぞれダブルクリックなんかで実行しっぱなして、&lt;br /&gt;http://localhost:8082/mylogin&lt;br /&gt;をブラウザから表示するとCAS側のログイン画面にリダイレクトされる。&lt;br /&gt;ここで認証に成功するともとのアプリに戻ってログインIDが表示される。&lt;br /&gt;&lt;br /&gt;CASサーバーがないのにCASのクライアントアプリを書くような羽目になったらこれで仮に開発を進めておくとか。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8789678787455856865?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8789678787455856865/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8789678787455856865' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8789678787455856865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8789678787455856865'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2009/01/pythoncas.html' title='pythonでCAS'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7561888808287311980</id><published>2008-10-15T21:42:00.004+09:00</published><updated>2009-03-03T11:59:57.627+09:00</updated><title type='text'>WSGI・謎の用法</title><content type='html'>WSGIは標準入力（相当のもの）と標準出力（相当のもの）を与えられて動く仕組みなのだから、UNIXのフィルタ処理みたいなものにも使えるのだろうか。と、ふと思いついたので作ってみた。以下に。&lt;br /&gt;&lt;br /&gt;下のスクリプトを適当な名前で保存して実行すると、WSGIアプリ用の簡易Webサーバーが立ち上がる。myapp関数がやってることは、標準入力から一行ずつテキストを受け取って、それを大文字化してからレスポンスとして返すというだけ。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def myapp(environ, start_response):&lt;br /&gt;    start_response('200 OK' , [('Content-Type', 'application/octet-stream')])&lt;br /&gt;    def myfilter(stream):&lt;br /&gt;        while True:&lt;br /&gt;            a = stream.readline()&lt;br /&gt;            if len(a) == 0: break&lt;br /&gt;            yield a.upper()&lt;br /&gt;    return myfilter(environ['wsgi.input'])&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    from wsgiref.simple_server import make_server&lt;br /&gt;    make_server('127.0.0.1', 8800, myapp).serve_forever()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;で、このサーバーにデータを投げつけてレスポンスを受け取るというスクリプトを別に用意する。ここでは filter1.py とでもする。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sys&lt;br /&gt;import socket&lt;br /&gt;server, port = '127.0.0.1', 8800&lt;br /&gt;s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;s.connect((server, port))&lt;br /&gt;s.send('GET / HTTP/1.0\n\n')&lt;br /&gt;for i in sys.stdin:&lt;br /&gt;    s.sendall(i)&lt;br /&gt;    a = s.recv(1024)&lt;br /&gt;    sys.stdout.write(a)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;で、動作テストは、例えばWindows系のコマンドプロンプトからなら&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;type some_text.txt | python filter1.py&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;とでも入力してみる。適当なファイルがなければ、このスクリプト自身を処理してみてもいい。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;type filter1.py | python filter1.py&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;で、得られるテキスト。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;HTTP/1.0 200 OK&lt;br /&gt;Date: Wed, 15 Oct 2008 12:42:23 GMT&lt;br /&gt;Server: WSGIServer/0.1 Python/2.5.2&lt;br /&gt;Content-Type: application/octet-stream&lt;br /&gt;&lt;br /&gt;IMPORT SYS&lt;br /&gt;IMPORT SOCKET&lt;br /&gt;SERVER, PORT = '127.0.0.1', 8800&lt;br /&gt;S = SOCKET.SOCKET(SOCKET.AF_INET, SOCKET.SOCK_STREAM)&lt;br /&gt;S.CONNECT((SERVER, PORT))&lt;br /&gt;S.SEND('GET / HTTP/1.0\N\N')&lt;br /&gt;FOR I IN SYS.STDIN:&lt;br /&gt;    S.SENDALL(I)&lt;br /&gt;    A = S.RECV(1024)&lt;br /&gt;    SYS.STDOUT.WRITE(A)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ワーイ、なんかフィルタコマンドっぽいものができた。WSGIで。&lt;br /&gt;&lt;br /&gt;普通のCGIスクリプトとかと違って、リクエストボディが全部終わらなくても受け取ったそばからレスポンスにして返してくれるから、どんなに巨大なデータを投げつけても、（ある意味）大丈夫。まさにフィルタコマンド。&lt;br /&gt;&lt;br /&gt;（なんかバッファリングの都合か、何回に一回かテキスト処理が途中で中断します。とりあえずまあいいや）&lt;br /&gt;&lt;br /&gt;(追記:2009.3.3 windowsのときは、標準出力を明示的にバイナリモードに設定しておかないとだめか。)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7561888808287311980?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7561888808287311980/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7561888808287311980' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7561888808287311980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7561888808287311980'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/10/wsgi.html' title='WSGI・謎の用法'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5258568085575456801</id><published>2008-10-14T19:11:00.002+09:00</published><updated>2008-10-14T20:08:27.708+09:00</updated><title type='text'>pythonでtar</title><content type='html'>WSGIの話がちょっと滞ったけど、再開するついでにtarの扱いについて。&lt;br /&gt;&lt;br /&gt;tarは、標準配布のtarfileモジュールを使って非常に簡単に扱える。無圧縮のtar、gzip圧縮したtar、bz2圧縮したtarが扱えるようだ。(Python2.5)&lt;br /&gt;&lt;br /&gt;tarfile.openで新しいtarファイルを作り、ファイルのフルパスないし相対パス名をどんどんaddしていけばよい。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import os&lt;br /&gt;import tarfile&lt;br /&gt;&lt;br /&gt;th = tarfile.open('test.tar', 'w')&lt;br /&gt;#th = tarfile.open('test.tar.bz2', 'w:bz2') &lt;--- こっちを有効にするとbz2圧縮&lt;br /&gt;for root, dirs, files in os.walk(r'c:\windows\media'):&lt;br /&gt;    for f in files:&lt;br /&gt;        fullpath = os.path.join(root, f)&lt;br /&gt;        print fullpath&lt;br /&gt;        th.add(fullpath)&lt;br /&gt;th.close()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ファイルを取り出すには、rオプションで開いて、extractでひとつづつ展開する。一度に展開するextactallもあるけど。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import tarfile&lt;br /&gt;&lt;br /&gt;th = tarfile.open('test.tar', 'r')&lt;br /&gt;#th = tarfile.open('test.tar.bz2', 'r:bz2')&lt;br /&gt;for item in th:&lt;br /&gt;    print item&lt;br /&gt;    th.extract(item)&lt;br /&gt;th.close()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5258568085575456801?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5258568085575456801/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5258568085575456801' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5258568085575456801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5258568085575456801'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/10/pythontar.html' title='pythonでtar'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3999654706222689811</id><published>2008-09-27T23:16:00.002+09:00</published><updated>2008-09-27T23:47:22.978+09:00</updated><title type='text'>WSGI探求(2)</title><content type='html'>前回のスクリプトのメインルーチン&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    from wsgiref.simple_server import make_server&lt;br /&gt;    make_server('127.0.0.1', 8780, myapp).serve_forever()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;は、myappというWSGIアプリケーションを使って、ローカルホストの8780番ポートでHTTPサーバーを実行してください、という意味。python2.5以降には、wsgirefというWSGIサーバーのサンプルが同梱されているので、これを使う。他にも、もっとちゃんと書かれたWSGIサーバーもあるので、それらが手元にあるのならそれを使っても同じこと。pasteなんかにもサーバー実装が含まれていた。とにかく、&lt;span style="font-weight:bold;"&gt;myappという名前のWSGIアプリ&lt;/span&gt;を動かすんだという点が最も重要。&lt;br /&gt;&lt;br /&gt;で、そのmyappとかいう名前のアプリケーションがどう定義されているかというと、こんなふう。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def myapp(environ, start_response):&lt;br /&gt;    if environ['PATH_INFO'] == '/hello':&lt;br /&gt;        return myapp2(environ, start_response)&lt;br /&gt;    start_response('200 OK' , [('Content-Type', 'text/html')])&lt;br /&gt;    message = 'you requested %s. HAZURE.' % environ['PATH_INFO']&lt;br /&gt;    return ['&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;p&amp;gt;', message, '&amp;lt;/p&amp;gt;&amp;lt;body&amp;gt;&amp;lt;/html&amp;gt;']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;関数は、environとstart_responseという引数を取る。仮引数の名前はなんでもいいけど。&lt;br /&gt;&lt;br /&gt;前者は、python辞書が必ず入ると決まっている。で、CGIスクリプトなんかで使う環境変数にあたるものはみんなこの辞書に入っている。だからPATH_INFOなんていうキーの値もこんな風に取り出せばよい。QUERY_STRINGとか、REMOTE_HOSTとか、おなじみの情報はみんなここから。&lt;br /&gt;CGIスクリプトが使う標準入力や標準出力も、この辞書に特定のキーの値として入ってくる。標準入力ならenviron['wsgi.input']、標準出力なら['wsgi.output']とか。他にもwsgi独自の値がいくつか入ってくるけど、今は重要でない。どこかでリファレンスを見れば全部載っている。&lt;br /&gt;なんせ、Webアプリとして参照したいであろう情報は、environ辞書にみんな入っている。&lt;br /&gt;&lt;br /&gt;で、次のstart_responseは、関数そのものが渡される。スクリプト中でstart_response(... なんてやっているように、これを呼び出して、レスポンスヘッダを作っている。&lt;br /&gt;CGIスクリプトならヘッダの書き出しも標準出力に対して行うところだけど、WSGIだとレスポンスの内容とヘッダをこんなふうに別々のルートで返させている。&lt;br /&gt;ちなみにレスポンスの内容のほうは、myappの返り値として素直に渡す。単なる文字列で返すんじゃなくて、わざわざリストの形にして返している点に注意。たぶん受け取り側で、for i in [返り値]: do [なんちゃら…] なんてしているのだろう。つまり、イテレータ（ジェネレータ）を返せってこと。これなら巨大なレスポンスを返すときに省メモリで済ますという工夫も可能になる。&lt;br /&gt;&lt;br /&gt;myappの中にmyapp2への呼び出しがある点については、後述。ミドルウェアとかの用語とからめて記す予定。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3999654706222689811?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3999654706222689811/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3999654706222689811' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3999654706222689811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3999654706222689811'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/wsgi2.html' title='WSGI探求(2)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8558091743913899616</id><published>2008-09-26T18:57:00.001+09:00</published><updated>2008-09-26T19:05:01.626+09:00</updated><title type='text'>WSGI探求(1)</title><content type='html'>WSGIってのは、CGIみたいにWeb上で動くスクリプト等の一般的な仕様を決めるもの。CGIよりもちょっと便利な使い方ができるように改良されている。現在はpython専用の仕様だけど、とてもシンプルなものなので、色々な言語に移植できるんじゃないかなという気もする。&lt;br /&gt;&lt;br /&gt;※たまに誤解されますが、CGIってのはperlで書かれたスクリプトじゃなくて、Webサーバーと手作りアプリケーションを連携させるための「仕様」のことです。標準入出力をこう使いなさいね、とか、あれこれの環境変数を渡しますよ、とか、そんなの。&lt;br /&gt;&lt;br /&gt;下のスクリプトでは、myappとmyapp2がそれぞれWSGIの仕様に則って書かれた完全なアプリケーション。&lt;br /&gt;これを適当なファイル名で保存して実行すれば、簡易Webサーバーが立ち上がり、今書いたWSGIアプリの動作をすぐに試せる。python2.5以降で。&lt;br /&gt;&lt;br /&gt;サーバーを終了するには、Ctrl+Cなりコンソールウィンドウを閉じてしまうなりすればよい。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def myapp2(environ, start_response):&lt;br /&gt;    start_response('200 OK' , [('Content-Type', 'text/html')])&lt;br /&gt;    message = 'you requested %s. HELLO! :)' % environ['PATH_INFO']&lt;br /&gt;    return ['&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;p&amp;gt;', message, '&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;']&lt;br /&gt;&lt;br /&gt;def myapp(environ, start_response):&lt;br /&gt;    if environ['PATH_INFO'] == '/hello':&lt;br /&gt;        return myapp2(environ, start_response)&lt;br /&gt;    start_response('200 OK' , [('Content-Type', 'text/html')])&lt;br /&gt;    message = 'you requested %s. HAZURE.' % environ['PATH_INFO']&lt;br /&gt;    return ['&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;p&amp;gt;', message, '&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;']&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    from wsgiref.simple_server import make_server&lt;br /&gt;    make_server('127.0.0.1', 8780, myapp).serve_forever()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;http://127.0.0.1:8780/&lt;br /&gt;とか&lt;br /&gt;http://127.0.0.1:8780/some/path&lt;br /&gt;とかにアクセスすると、myappが返答を返してくれて、'HAZURE' とか言われる。&lt;br /&gt;&lt;br /&gt;http://127.0.0.1:8780/hello&lt;br /&gt;にアクセスしたときは、myappはリクエストををmyapp2に転送してくれて、もうちょっと丁寧な挨拶が返ってくる。&lt;br /&gt;&lt;br /&gt;このスクリプトはどういう意味なんだい、とか、なんで従来のCGIじゃダメなんだい、とか、とかそんな話は追って書く、予定&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8558091743913899616?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8558091743913899616/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8558091743913899616' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8558091743913899616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8558091743913899616'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/wsgi1.html' title='WSGI探求(1)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8798332322934940933</id><published>2008-09-25T20:05:00.004+09:00</published><updated>2008-09-25T20:23:43.229+09:00</updated><title type='text'>pythonで四川省</title><content type='html'>「四川省」という名前で知られているゲームをpythonで書いてみた。麻雀牌を順に取り去っていくやつ。&lt;br /&gt;勝手に問題を作って勝手に解いていくというデモなので、見てるだけ。&lt;br /&gt;グラフィカルな表示は、まだなし。&lt;br /&gt;&lt;br /&gt;同じ牌どうしを、２回まで曲がれるルートでくっつけて取り去るところがゲームのキモ。&lt;br /&gt;まず同じ牌を適当に見つけてから、これを取ることができるかを考える(find_wayメソッド)。２回まで曲がれるということは、直線ルートを3回分つなげてよいということ。色々なパターンがあるが、実は最初の一回分の直線だけ決まればあとのルートは必然的に決まるので、最初の一回を全パターン分作り出し(enum_first_steps)て、残り(complete_way)が障害なく目的の牌に通じているかを評価する。&lt;br /&gt;&lt;br /&gt;ここらへんをみんなクラスの内部に押し込めてしまって、メインルーチンは単純になった。すなわち、find_removable_pair で取れるペアを探してみて、見つかったらremove_pair で実際に取り去って、dumpで表示、あとはループ。見つからなくなったら終了。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import random&lt;br /&gt;&lt;br /&gt;VERTICAL = (0, 1)&lt;br /&gt;HORIZONTAL = (1, 0)&lt;br /&gt;&lt;br /&gt;def signed_range(start, end):&lt;br /&gt;    if start &gt; end:&lt;br /&gt;        for i in xrange(start - end): yield -1&lt;br /&gt;    else:&lt;br /&gt;        for i in xrange(end - start): yield 1&lt;br /&gt;&lt;br /&gt;class Step(object):&lt;br /&gt;    def __init__(self, orient, distance):&lt;br /&gt;        self.vx = orient[0]&lt;br /&gt;        self.vy = orient[1]&lt;br /&gt;        self.distance = distance&lt;br /&gt;&lt;br /&gt;class Sisensho(object):&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.board = [[0 for i in xrange(10)] for i in xrange(20)]&lt;br /&gt;        tiles = []&lt;br /&gt;        self.searchpath = []&lt;br /&gt;        for i in xrange(36): tiles.extend((i+1,)*4)&lt;br /&gt;        random.shuffle(tiles)&lt;br /&gt;        for x in xrange(18):&lt;br /&gt;            for y in xrange(8):&lt;br /&gt;                self.board[x+1][y+1] = tiles.pop()&lt;br /&gt;                self.searchpath.append((x+1, y+1),)&lt;br /&gt;        random.shuffle(self.searchpath)&lt;br /&gt;        self.last_remove_track = []&lt;br /&gt;&lt;br /&gt;    def dump(self):&lt;br /&gt;        TILE_IMAGE = ' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'&lt;br /&gt;        for y in xrange(10):&lt;br /&gt;            tmp = []&lt;br /&gt;            for x in xrange(20):&lt;br /&gt;                if self.last_remove_track.count((x, y)):&lt;br /&gt;                    tmp.append('*')&lt;br /&gt;                else:&lt;br /&gt;                    tmp.append(TILE_IMAGE[self.board[x][y]])&lt;br /&gt;            print ''.join(tmp)&lt;br /&gt;                &lt;br /&gt;    def enum_first_steps(self, ox, oy):&lt;br /&gt;        def _goer(direction, sign):&lt;br /&gt;            d = 0&lt;br /&gt;            while True:&lt;br /&gt;                d += 1&lt;br /&gt;                x, y = (ox+direction[0]*d*sign,&lt;br /&gt;                          oy+direction[1]*d*sign)&lt;br /&gt;                if x &lt; 0 or x &gt;= 20: break&lt;br /&gt;                if y &lt; 0 or y &gt;= 10: break&lt;br /&gt;                if self.board[x][y] != 0: break&lt;br /&gt;                yield Step(direction, d*sign)&lt;br /&gt;        yield Step(VERTICAL, 0)&lt;br /&gt;        yield Step(HORIZONTAL, 0)&lt;br /&gt;        e = [_goer(VERTICAL, -1), _goer(HORIZONTAL, 1),&lt;br /&gt;              _goer(VERTICAL, 1), _goer(HORIZONTAL, -1)]&lt;br /&gt;        while e:&lt;br /&gt;          ee = []&lt;br /&gt;          for i in e:&lt;br /&gt;            try:&lt;br /&gt;              yield i.next()&lt;br /&gt;              ee.append(i)&lt;br /&gt;            except StopIteration:&lt;br /&gt;              pass&lt;br /&gt;          e = ee&lt;br /&gt;&lt;br /&gt;    def complete_way(self, ox, oy, tx, ty, initial_step):&lt;br /&gt;        xd = (tx - (ox+initial_step.vx*initial_step.distance))&lt;br /&gt;        yd = (ty - (oy+initial_step.vy*initial_step.distance))&lt;br /&gt;        if initial_step.vx == 0: #VERTICAL&lt;br /&gt;            tmp = (initial_step, Step(HORIZONTAL, xd), Step(VERTICAL, yd))&lt;br /&gt;        else:&lt;br /&gt;            tmp = (initial_step, Step(VERTICAL, yd),Step (HORIZONTAL, xd))&lt;br /&gt;        return filter(lambda x: (x.distance!=0), tmp)&lt;br /&gt;&lt;br /&gt;    def trace_way(self, x, y, way):&lt;br /&gt;        tx, ty = (x, y)&lt;br /&gt;        tmp = [(x, y), ]&lt;br /&gt;        for w in way:&lt;br /&gt;            for i in signed_range(0, w.distance):&lt;br /&gt;                tx += w.vx * i&lt;br /&gt;                ty += w.vy * i&lt;br /&gt;                tmp.append((tx, ty),)&lt;br /&gt;        return tmp&lt;br /&gt;&lt;br /&gt;    def find_way(self, ox, oy, tx, ty):&lt;br /&gt;        for i in self.enum_first_steps(ox, oy):&lt;br /&gt;            way = self.complete_way(ox, oy, tx, ty, i)&lt;br /&gt;            a = self.trace_way(ox, oy, way)&lt;br /&gt;            for aa in a[1:-1]:&lt;br /&gt;                if s.board[aa[0]][aa[1]] != 0: break&lt;br /&gt;            else:&lt;br /&gt;                return a&lt;br /&gt;        return None&lt;br /&gt;&lt;br /&gt;    def find_pair(self):&lt;br /&gt;        for (i, v) in enumerate(self.searchpath):&lt;br /&gt;            c = self.board[v[0]][v[1]]&lt;br /&gt;            if c != 0:&lt;br /&gt;                for j in xrange(i+1, len(self.searchpath)):&lt;br /&gt;                    vv = self.searchpath[j]&lt;br /&gt;                    if self.board[vv[0]][vv[1]] == c:&lt;br /&gt;                        return (v, vv)&lt;br /&gt;        return None&lt;br /&gt;&lt;br /&gt;    def find_removable_pair(self):&lt;br /&gt;        for (i, v) in enumerate(self.searchpath):&lt;br /&gt;            c = self.board[v[0]][v[1]]&lt;br /&gt;            if c != 0:&lt;br /&gt;                for j in xrange(i+1, len(self.searchpath)):&lt;br /&gt;                    vv = self.searchpath[j]&lt;br /&gt;                    if self.board[vv[0]][vv[1]] == c:&lt;br /&gt;                        way = self.find_way(v[0],v[1],vv[0],vv[1]) &lt;br /&gt;                        if way: return (v, vv, way)&lt;br /&gt;        return None&lt;br /&gt;&lt;br /&gt;    def remove_pair(self, pairinfo):&lt;br /&gt;        p1, p2, way = pairinfo&lt;br /&gt;        self.board[p1[0]][p1[1]] = 0&lt;br /&gt;        self.board[p2[0]][p2[1]] = 0&lt;br /&gt;        self.searchpath.remove(p1)&lt;br /&gt;        self.searchpath.remove(p2)&lt;br /&gt;        self.last_remove_track = way&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    s = Sisensho()&lt;br /&gt;    s.dump()&lt;br /&gt;    while True:&lt;br /&gt;        p = s.find_removable_pair()&lt;br /&gt;        if not p: break&lt;br /&gt;        s.remove_pair(p)&lt;br /&gt;        s.dump()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;実行中の表示例。使う牌は36種類x4枚づつなので、0-9とA-Zでちょうど代用できた。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; STAR5KENZ5HP3JGMNT &lt;br /&gt; DLP8EGIT    0WR8O  &lt;br /&gt; BSG1HXAOU9 *804GVD &lt;br /&gt; IU3RJ2C96O *X578YN &lt;br /&gt; VY7I1 TZ   *    C7 &lt;br /&gt; O4UMX U    * 2I W  &lt;br /&gt; 6Y LDK B           &lt;br /&gt; N7 X5D        Y  R &lt;br /&gt;                    &lt;br /&gt;                    &lt;br /&gt; STAR5KENZ5HP3JGMNT &lt;br /&gt; DLP8EGIT    0WR8O  &lt;br /&gt; BSG1HXAOU9  804GVD &lt;br /&gt; IU3RJ2C96O  *578YN &lt;br /&gt; VY7I1 TZ    *   C7 &lt;br /&gt; O4UMX U     *2I W  &lt;br /&gt; 6Y LDK B    *      &lt;br /&gt; N7 *5D      * Y  R &lt;br /&gt;    **********      &lt;br /&gt;                    &lt;br /&gt; STAR5KENZ5HP3JGMNT &lt;br /&gt; DLP8EGIT    0WR8O  &lt;br /&gt; BSG1HXAOU9  *04GVD &lt;br /&gt; IU3RJ2C96O  *57*YN &lt;br /&gt; VY7I1 TZ    ****C7 &lt;br /&gt; O4UMX U      2I W  &lt;br /&gt; 6Y LDK B           &lt;br /&gt; N7  5D        Y  R &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;平均して、2回に1回くらいクリアに成功するみたい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8798332322934940933?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8798332322934940933/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8798332322934940933' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8798332322934940933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8798332322934940933'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/python_25.html' title='pythonで四川省'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-9217384125800817240</id><published>2008-09-23T19:34:00.003+09:00</published><updated>2008-09-24T00:04:16.389+09:00</updated><title type='text'>pythonでさめがめ(2)</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_Zi6PKIg2V_I/SNkFZ_GCbQI/AAAAAAAAAx4/Wkn3vFG5r_8/s1600-h/samegame.gif"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_Zi6PKIg2V_I/SNkFZ_GCbQI/AAAAAAAAAx4/Wkn3vFG5r_8/s320/samegame.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5249232784668650754" /&gt;&lt;/a&gt;&lt;br /&gt;前のエントリで作ったSameGameBoardクラスを実際に使って、さめがめを最低限プレイできる程度の実装をしてみた。要pygame。&lt;br /&gt;&lt;br /&gt;ライブラリの読み込みパス（大抵は本スクリプトと同じディレクトリ上）に、samegame.pyが置いてあること。&lt;br /&gt;&lt;br /&gt;スコアも何にも出ないのであまり面白くはないが、とつぜんさめがめがやりたくなったときに、この程度で足りることもある。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from samegame import SameGameBoard&lt;br /&gt;&lt;br /&gt;import pygame&lt;br /&gt;import pygame.locals as C&lt;br /&gt;&lt;br /&gt;class SameGame(object):&lt;br /&gt;&lt;br /&gt;    clr = [ 0x000000, 0xff00ff, 0xff8000, 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, 0xffffff]&lt;br /&gt;&lt;br /&gt;    def __init__(self, width, height, variety):&lt;br /&gt;        self.b = SameGameBoard(width, height, variety)&lt;br /&gt;        pygame.display.set_mode((640, 480))&lt;br /&gt;        self.c = pygame.display.get_surface()&lt;br /&gt;&lt;br /&gt;    def run(self):&lt;br /&gt;        self.draw()&lt;br /&gt;        while True:&lt;br /&gt;            e = pygame.event.poll()&lt;br /&gt;            if e.type == C.QUIT:&lt;br /&gt;                break&lt;br /&gt;            if e.type == C.MOUSEMOTION:&lt;br /&gt;                (x, y) = e.pos&lt;br /&gt;                (x, y) = (x // 14, y // 14)&lt;br /&gt;                if (x &gt;= 0) and (x &lt; self.b.width) and (y &gt;= 0) and (y &lt; self.b.height):&lt;br /&gt;                    self.b.setHighLight(x, y)&lt;br /&gt;            if e.type == C.MOUSEBUTTONDOWN:&lt;br /&gt;                self.b.shootHighLight()&lt;br /&gt;            self.draw()&lt;br /&gt;&lt;br /&gt;    def draw(self):&lt;br /&gt;        self.c.fill(0x000000)&lt;br /&gt;        for i in xrange(self.b.width):&lt;br /&gt;            for j in xrange(self.b.height):&lt;br /&gt;                p = i+j*self.b.width&lt;br /&gt;                if self.b.highlightregion[p] != 0:&lt;br /&gt;                    pygame.draw.rect(self.c, self.clr[-1],&lt;br /&gt;                     (i*14, j*14, 13, 13), 0)&lt;br /&gt;                else:&lt;br /&gt;                    pygame.draw.rect(self.c, self.clr[self.b.content[p]],&lt;br /&gt;                     (i*14, j*14, 13, 13), 0)&lt;br /&gt;        pygame.display.flip()&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    pygame.init()&lt;br /&gt;    try:&lt;br /&gt;        SameGame(40, 32, 4).run()&lt;br /&gt;    finally:&lt;br /&gt;        pygame.quit()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-9217384125800817240?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/9217384125800817240/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=9217384125800817240' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/9217384125800817240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/9217384125800817240'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/python2.html' title='pythonでさめがめ(2)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SNkFZ_GCbQI/AAAAAAAAAx4/Wkn3vFG5r_8/s72-c/samegame.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1683718659527169411</id><published>2008-09-23T19:27:00.002+09:00</published><updated>2008-09-23T19:33:59.535+09:00</updated><title type='text'>pythonでさめがめ(1)</title><content type='html'>「さめがめ」をなんとなくpythonで実装してみる。&lt;br /&gt;下のリストはグラフィカルな描画ルーチンを含まない、データ構造と振る舞いを定義するだけのクラス。あとでimportするから、samegame.pyとでもして保存しておく。&lt;br /&gt;&lt;br /&gt;setHighLightメソッドとshootHighLightメソッドが重要で、前者はある点を基点として同じ色のマスを順次探していって、一度に消せる隣接マスを決める。後者はあらかじめ探索しておいた隣接マスを実際に消して、まずはタテ方向に、次にヨコ方向に「詰める」。&lt;br /&gt;&lt;br /&gt;SameGameBoardクラスのコンストラクタは三つの引数を取る。横サイズ、縦サイズ、コマの種類。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import random&lt;br /&gt;&lt;br /&gt;class SameGameBoard(object):&lt;br /&gt;    def __init__(self, width, height, variation):&lt;br /&gt;        self.width, self.height = width, height&lt;br /&gt;        self.content = [random.randint(1, variation) for i in xrange(width*height)]&lt;br /&gt;        self.highlightregion = [0 for i in xrange(width*height)]&lt;br /&gt;&lt;br /&gt;    def _getNeighbours(self, offset):&lt;br /&gt;        x = offset % self.width&lt;br /&gt;        y = offset // self.width&lt;br /&gt;        tmp = []&lt;br /&gt;        if x &gt; 0:               tmp.append(offset-1)&lt;br /&gt;        if x &lt; (self.width-1):  tmp.append(offset+1)&lt;br /&gt;        if y &gt; 0:               tmp.append(offset-self.width)&lt;br /&gt;        if y &lt; (self.height-1): tmp.append(offset+self.width)&lt;br /&gt;        return tmp&lt;br /&gt;&lt;br /&gt;    def resetHighLight(self):&lt;br /&gt;        self.highlightregion = [0 for i in xrange(self.width*self.height)]&lt;br /&gt;&lt;br /&gt;    def setHighLight(self, x, y):&lt;br /&gt;        self.resetHighLight()&lt;br /&gt;        h = self.highlightregion #shortcut&lt;br /&gt;        c = self.content         #shortcut&lt;br /&gt;        seed = c[x+y*self.width]&lt;br /&gt;        if seed == 0: return&lt;br /&gt;        h[x+y*self.width] = 1&lt;br /&gt;        size = 1&lt;br /&gt;        while True:&lt;br /&gt;            cnt = 0&lt;br /&gt;            for i in xrange(self.width*self.height):&lt;br /&gt;                if h[i] == 1:&lt;br /&gt;                    for k in self._getNeighbours(i):&lt;br /&gt;                        if c[k] == seed and h[k] == 0:&lt;br /&gt;                            h[k] = 1&lt;br /&gt;                            cnt += 1&lt;br /&gt;                            size += 1&lt;br /&gt;                h[i] == 2&lt;br /&gt;            if cnt == 0: break&lt;br /&gt;        if size == 1:&lt;br /&gt;            self.resetHighLight()&lt;br /&gt;&lt;br /&gt;    def shootHighLight(self):&lt;br /&gt;        c = self.content #shortcut&lt;br /&gt;        # vanish phase&lt;br /&gt;        for i in xrange(self.width*self.height):&lt;br /&gt;            if self.highlightregion[i] != 0: c[i] = 0&lt;br /&gt;        self.resetHighLight()&lt;br /&gt;        # drop phase&lt;br /&gt;        for i in xrange(self.width):&lt;br /&gt;            while True:&lt;br /&gt;                cnt = 0&lt;br /&gt;                for j in xrange(self.height-1):&lt;br /&gt;                    offset = i+(self.height-1-j)*self.width&lt;br /&gt;                    if c[offset] == 0 and c[offset-self.width] != 0:&lt;br /&gt;                        c[offset] = c[offset-self.width]&lt;br /&gt;                        c[offset-self.width] = 0&lt;br /&gt;                        cnt += 1&lt;br /&gt;                if cnt == 0: break&lt;br /&gt;        # cram phase&lt;br /&gt;        while True:&lt;br /&gt;            cnt = 0&lt;br /&gt;            for i in xrange(self.width-1):&lt;br /&gt;                for j in xrange(self.height):&lt;br /&gt;                    if c[i+j*self.width] != 0: break&lt;br /&gt;                else:&lt;br /&gt;                    for jj in xrange(self.height):&lt;br /&gt;                        offset = jj*self.width&lt;br /&gt;                        for ii in xrange(i, self.width-1):&lt;br /&gt;                            if c[offset+ii+1] != 0: cnt += 1&lt;br /&gt;                            c[offset+ii] = c[offset+ii+1]&lt;br /&gt;                        c[offset+self.width-1] = 0&lt;br /&gt;            if cnt == 0: break&lt;br /&gt;&lt;br /&gt;    def dump(self):&lt;br /&gt;        for i in xrange(self.height):&lt;br /&gt;            offset = i * self.width&lt;br /&gt;            for j in xrange(self.width):&lt;br /&gt;                if self.highlightregion[offset+j] != 0:&lt;br /&gt;                    print "!",&lt;br /&gt;                else:&lt;br /&gt;                    print self.content[offset+j],&lt;br /&gt;            print&lt;br /&gt;        print "---"&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    b = SameGameBoard(32, 24, 3)&lt;br /&gt;    b.dump()&lt;br /&gt;    while True:&lt;br /&gt;        b.setHighLight(0, 23)&lt;br /&gt;        b.dump()&lt;br /&gt;        b.shootHighLight()&lt;br /&gt;        b.dump()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1683718659527169411?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1683718659527169411/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1683718659527169411' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1683718659527169411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1683718659527169411'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/python1.html' title='pythonでさめがめ(1)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3757587757049187904</id><published>2008-09-02T11:06:00.004+09:00</published><updated>2008-09-02T11:49:47.982+09:00</updated><title type='text'>pythonでパスワードをハッシュ化</title><content type='html'>スクリプト中にパスワードを直接書かずに、特定のパスワードと比較してログイン処理などを書きたいことがある。md5モジュールを使ってできる。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import md5&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; md5.md5('secretpassphrase').digest()&lt;br /&gt;')mMD\xa2\x9b{+\xf2\x19\xc2-+\x8b\xa5\x19'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;こんな風にハッシュ値（ダイジェスト値ともいう）を出しておいて、スクリプトにはこれを使って比較ルーチンを書けばよい。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import md5&lt;br /&gt;pass_hash = ')mMD\xa2\x9b{+\xf2\x19\xc2-+\x8b\xa5\x19'&lt;br /&gt;r = raw_input('input password:')&lt;br /&gt;if md5.md5(r).digest() == pass_hash:&lt;br /&gt;    print "login OK"&lt;br /&gt;else:&lt;br /&gt;    print "login NG"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ダイジェスト値から元のパスワードを導き出すのは、事実上不可能といわれている。なので万一スクリプトが漏れたとしてもパスワードはばれない。まあ、あまり単純なパスワードだったら、総当りでハッシュ計算し続ければいつかばれてしまうけど。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3757587757049187904?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3757587757049187904/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3757587757049187904' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3757587757049187904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3757587757049187904'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/python.html' title='pythonでパスワードをハッシュ化'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5224253658122431985</id><published>2008-09-02T10:37:00.002+09:00</published><updated>2008-09-02T10:58:32.684+09:00</updated><title type='text'>pythonでwebサイトの構成チェック</title><content type='html'>ローカルファイルにコピーしたWebサイトのファイル群について、互いのリンク関係を抜き出して調べたい。&lt;br /&gt;&lt;br /&gt;まずファイルの列挙には、os.walk() を使う。引数は始点ディレクトリ。これは下にあるディレクトリを再帰的に調べて、（現在のディレクトリパス、その下のディレクトリ名一覧、その下のファイル名一覧）というタプルを列挙するイテレータを返してくるので、forループで処理する。&lt;br /&gt;&lt;br /&gt;.htm または .html で終わるファイル名のものについては、中身の調査をする。具体的には、該当ファイルの中身を全部読み込んでから、href=.... というパターンをすべて探し出して、リンク先を抜き出す(正規表現r1)。&lt;br /&gt;&lt;br /&gt;リンクの表現は、スキーム名のついた完全URLだったり、相対URLだったりする。特に相対URLだったときは、os.pathモジュールを使って、これらを正規化して表示させる。os.path.normpathが面白くて、これは 'a/b/c/../../d' といったパスを 'a/d' に整理したりという働きをする。windowsでなら、スラッシュは逆スラッシュになる。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import os&lt;br /&gt;import re&lt;br /&gt;&lt;br /&gt;r1 = re.compile(r'href="?(.+?)"?[ &gt;]', re.I)&lt;br /&gt;r2 = re.compile(r'^(http|file|javascript|mailto):', re.I)&lt;br /&gt;&lt;br /&gt;def search_link(filename):&lt;br /&gt;    print "[%s]" % filename&lt;br /&gt;    t = open(filename).read()&lt;br /&gt;    for i in r1.findall(t):&lt;br /&gt;        if r2.match(i):&lt;br /&gt;            print i&lt;br /&gt;        else:&lt;br /&gt;            print os.path.normpath(os.path.join(os.path.dirname(filename), i))&lt;br /&gt;&lt;br /&gt;for dname, dirs, files in os.walk("."):&lt;br /&gt;    for i in files:&lt;br /&gt;        if i.endswith(".htm") or i.endswith(".html"):&lt;br /&gt;            search_link(os.path.join(dname, i))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5224253658122431985?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5224253658122431985/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5224253658122431985' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5224253658122431985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5224253658122431985'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/09/pythonweb.html' title='pythonでwebサイトの構成チェック'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-120706791059660638</id><published>2008-08-13T01:38:00.002+09:00</published><updated>2008-08-13T01:45:14.760+09:00</updated><title type='text'>pythonで8queens</title><content type='html'>ちょっと前に書いた8queensを解くスクリプトを置いておく。&lt;br /&gt;8queensってのは、チェス版(8x8)の上に8体のクイーンの駒を置いて、互いに取りっこできないように配置するというパズル。クイーンは前後左右斜めに何マスでも動けるとても強力なコマ。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#BSIZE = 10&lt;br /&gt;BSIZE = 8&lt;br /&gt;&lt;br /&gt;class chessboard:&lt;br /&gt;&lt;br /&gt;  def __init__(self):&lt;br /&gt;    self.p = [0] * BSIZE&lt;br /&gt;    self.pt = 0&lt;br /&gt;&lt;br /&gt;  def __str__(self):&lt;br /&gt;    return self.p.__str__()&lt;br /&gt;&lt;br /&gt;  def put(self, row, pos):&lt;br /&gt;    self.p[row-1] = pos&lt;br /&gt;    self.pt = row&lt;br /&gt;&lt;br /&gt;  def check_corride(self):&lt;br /&gt;    for i in range(1, self.pt):&lt;br /&gt;      d = 1&lt;br /&gt;      for j in range(i+1, self.pt+1):&lt;br /&gt;        if self.p[i-1] == self.p[j-1]:&lt;br /&gt;          return True&lt;br /&gt;        if self.p[i-1]+d == self.p[j-1]:&lt;br /&gt;          return True&lt;br /&gt;        if self.p[i-1]-d == self.p[j-1]:&lt;br /&gt;          return True&lt;br /&gt;        d = d + 1&lt;br /&gt;&lt;br /&gt;    return False&lt;br /&gt;&lt;br /&gt;def testloop(b, row):&lt;br /&gt;&lt;br /&gt;   for i in range(BSIZE):&lt;br /&gt;     b.put(row, i+1)&lt;br /&gt;     if b.check_corride():&lt;br /&gt;       continue&lt;br /&gt;     else:&lt;br /&gt;       if row &lt; BSIZE:&lt;br /&gt;         testloop(b, row+1)&lt;br /&gt;       else:&lt;br /&gt;         print "queen", b&lt;br /&gt;&lt;br /&gt;testloop(chessboard(), 1)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(実行結果)&lt;br /&gt;queen [1, 5, 8, 6, 3, 7, 2, 4]&lt;br /&gt;queen [1, 6, 8, 3, 7, 4, 2, 5]&lt;br /&gt;queen [1, 7, 4, 6, 8, 2, 5, 3]&lt;br /&gt;queen [1, 7, 5, 8, 2, 4, 6, 3]&lt;br /&gt;....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;一行の表示が一とおり分の解。順に、一番上の列で左から1番目に配置、二番目の列で左から5番目に配置…というように読む。&lt;br /&gt;BSIZEの値を8より大きくしても、ちゃんと解はあるみたい。解くの遅いけど。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-120706791059660638?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/120706791059660638/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=120706791059660638' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/120706791059660638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/120706791059660638'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/08/python8queens.html' title='pythonで8queens'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-2600845977548472152</id><published>2008-08-04T21:40:00.000+09:00</published><updated>2008-08-04T21:41:24.255+09:00</updated><title type='text'>また滞った</title><content type='html'>次はMicroApacheのことを書いてみよう、と備忘的に書いておくテスト&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-2600845977548472152?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/2600845977548472152/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=2600845977548472152' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2600845977548472152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2600845977548472152'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/08/blog-post.html' title='また滞った'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-6386965742611970974</id><published>2008-07-22T00:08:00.004+09:00</published><updated>2008-07-22T00:48:19.652+09:00</updated><title type='text'>pythonのメモと、その他の読書</title><content type='html'>pythonを相変わらずチマチマいじっている。今日はpython付属のCGIHTTPRequestHandlerを使ってCGIスクリプトのテストをしていて、Locationヘッダをまともに扱ってくれない点を調べていた。ApacheかなんかからCGIを叩かれたときは、そこで&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;print "Location: http://どこそこ…&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;なんていうヘッダを標準出力に書いたらレスポンスコードを302番なんかに切り替えてくれるのに、今のヤツでは普通のOK、つまり200番を返すだけなので、ブラウザはリダイレクトだと気づいてくれない。そういう仕様かな、と考えてソース読んだら、もろにその旨のコメントが書いてあった。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Note that status code 200 is sent prior to execution of a CGI script, so&lt;br /&gt;scripts cannot send other status codes such as 302 (redirect).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これの改造はちょっと大変そうなので、無理せずにApacheか何か持ち出して続きを開発するか。&lt;br /&gt;&lt;br /&gt;あとはこれと関係ない読書メモ。&lt;br /&gt;&lt;br /&gt;『小倉百人一首を学ぶ人のために』糸井通浩編、世界思想社。別に百人一首が好きなわけでもないし古典が好きなわけでもないけど、ちょっと考えるところがあって百人一首を暗記してみようと思ったので。今は25個くらいまで歌の解説を読みながら覚えたり忘れたり。そうか百人一首の中の歌ってこんな意味だったりするのか、とか気づいたりもして、案外勉強になっている。&lt;br /&gt;&lt;br /&gt;『虚数の情緒』吉田武著、東海大学出版会。分厚い本。自然数の説明からはじまってその性質をいろいろいじくって見せるうちに、そこから整数という考えが必要になってきた理由、またそこから有理数、無理数、実数、果ては虚数までが必要になってきた理由を、断絶のない自然なストーリーで、また物理、音楽、生物学なんかも縦横に援用しながら語りぬく。こういった事柄の本質をを心底理解していないとこんな本書けないんだろうなあ、と思う。副題は「中学生からの全方位独学法」。中学生に理解させることを目指して、しかも内容は変なたとえ話でゴマかさない、本物の数学。これぞ学者の書く本だ。すごいぞ。&lt;br /&gt;と言っておきながら、流し読み程度しかできていない。いつか中学生くらいの年代と数学を学ぶ機会でもあるのなら、この本のことを思い出さなくてはいけない。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-6386965742611970974?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/6386965742611970974/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=6386965742611970974' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6386965742611970974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6386965742611970974'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python_22.html' title='pythonのメモと、その他の読書'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8847808133936881587</id><published>2008-07-18T21:46:00.002+09:00</published><updated>2008-07-18T21:51:44.181+09:00</updated><title type='text'>pythonで壁紙変更</title><content type='html'>Windows専用のサンプルスクリプト。とりあえずWinXPとpython2.5で動作確認した。&lt;br /&gt;下のスクリプトを適当な名前で保存して、ダブルクリックで実行するだけ。&lt;br /&gt;システムディレクトリ下にあるビットマップファイルを適当に選んで、壁紙変更のWin32APIを実行する、と思う。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import ctypes&lt;br /&gt;import glob&lt;br /&gt;import random&lt;br /&gt;u32 = ctypes.windll.LoadLibrary('user32.dll')&lt;br /&gt;bb = glob.glob(r'c:\windows\*.bmp')&lt;br /&gt;fname = random.choice(bb)&lt;br /&gt;u32.SystemParametersInfoA(20, 0, fname, 2 | 1)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ctypesライブラリは、python2.5から標準配布だけど、それ以外はどうやって導入するかは知らない。&lt;br /&gt;あと、SystemParametersInfoAの中でいくつか数字を決めうちするのは、定数名をちゃんと示しておらず手抜き。APIの名前でググったら色々出てきます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8847808133936881587?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8847808133936881587/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8847808133936881587' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8847808133936881587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8847808133936881587'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python_18.html' title='pythonで壁紙変更'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5865816286213316823</id><published>2008-07-17T15:41:00.005+09:00</published><updated>2008-07-17T18:48:05.404+09:00</updated><title type='text'>pythonの付属HTTPサーバーを読む</title><content type='html'>pythonの標準ライブラリにあるWebサーバーは、サーバーとハンドラという要素に分けて設計されている。&lt;br /&gt;&lt;br /&gt;サーバー部は、クライアントからの接続を待ち受けるという役割を受け持っている。接続が確立すると、残りの仕事はハンドラ部に振ってしまって、自分は次の接続を待ち受けるといった分業体制が成り立っている。&lt;br /&gt;振ってしまって自分は次の…とは書いたが、実際は今の実装ではハンドラ部が仕事を終えるまで、サーバー部は何もできず（次の接続待ちにも移れず）にボンヤリ待っているだけ。もっと本気で実装するなら、ここらへんをマルチスレッドだか何だかにすることになるだろう。（ThreadingMixInとかの仕組みもモジュールから見つけたのだけど、ちゃんといじってない）&lt;br /&gt;&lt;br /&gt;サーバー部の基底になっているモジュールはBaseServer、ハンドラ部の基底になっているモジュールはBaseRequestHandler。&lt;br /&gt;&lt;br /&gt;BaseServerは、クライアントからのリクエストを受けてハンドラに仕事を振るという基本的な動きを定義している。ハンドラに振るとは、ここでは、ハンドラクラスのインスタンスを生成するということ。でも、生成したインスタンスのその後については、サーバー側としてはもう関心がない。ハンドラの__init__メソッド、つまりコンストラクタが実行されることが重要みたいだ。ハンドラにとって大事な仕事は全部コンストラクタ、またはコンストラクタが呼び出すメソッド上に書いてあると想定している。&lt;br /&gt;リクエスト受けて、ハンドラに振って、またリクエスト受けて…といった、長時間動くサーバーとしての動作を、serve_foreverという名前のメソッドで定義している。&lt;br /&gt;&lt;br /&gt;BaseServerを継承して書かれているのがTCPServerで、クライアントからのリクエストを受ける部分が具体的にソケット通信の手続きとして書いてある。UDPServerも書かれているけど今回は触れない。&lt;br /&gt;&lt;br /&gt;TCPServerを継承して、HTTPServerが書かれている。でもあまりTCPServerから進んだことはしていなくて、自分のホスト名とかポート名とかを使いやすくしておこうとかそんな程度に見える。&lt;br /&gt;&lt;br /&gt;サーバー部はここまで。&lt;br /&gt;&lt;br /&gt;ハンドラ部の基底クラスであるBaseRequestHandlerは、一般的なリクエストの処理順序を決めているだけ。すなわち、__init__（コンストラクタ）のタイミングで、サーバー部からリクエストの文脈を受け取って、setupして、handleして、finishすること、と。リクエストの文脈とは具体的に何なのか、setupやらhandleやらとは具体的にどういう仕事なのかは全然決めていない。&lt;br /&gt;&lt;br /&gt;BaseRequestHandlerを継承して書かれたStreamRequestHandlerは、このクラスが入力ストリームと出力ストリームを持つこと、finishではこれをcloseすべしということを決めている。でも相変わらずこれを使って何をするとは決めていない。&lt;br /&gt;&lt;br /&gt;StreamRequestHandlerを継承して書かれたBaseHTTPRequestHandlerになると、かなりウェブサーバーっぽい挙動ができるようになる。これのhandleメソッドでは、HTTPのリクエストメソッド(GET、POST、HEAD…)を調べてこれに対応するクラスメソッドを実行することを記述している。GETならdo_GET、POSTならdo_POST、といった具合に。でもこれらをこのクラス自身では準備していないから、該当の処理ルーチン不明ということで、すべてのHTTPリクエストは501のレスポンスコードをクライアント（出力ストリーム）に返す。&lt;br /&gt;&lt;br /&gt;BaseHTTPRequestHandlerを継承して書かれたSimpleHTTPRequestHandlerが、やっとクライアント側にとって意味のある動作をするようになる。このハンドラはdo_GETとdo_HEADを実装していて、あらかじめ決めた基準ディレクトリ下のファイルを、HTTPのリクエストパスに従って選び、これの内容を出力ストリームに流すという動作を実現している。リクエストパスがディレクトリそのものに対応するときは、該当ディレクトリのファイルリストを提供する。つまり、これで静的なWebサイトを（ある程度）提供できる程度のものになった。&lt;br /&gt;&lt;br /&gt;CGIRequestHandlerは、SimpleHTTPServerを継承して、さらにdo_POSTを実装した。環境変数をそろえ、外部CGIスクリプトを実行し、標準入力にリクエストからの入力ストリームをつなげ、標準出力を受け取ってクライアント側に流す。つまりCGIのインターフェースに決められた動作をサポートする。これでCGIスクリプトを叩くことができるようになった。POSTメソッドでしか起動できない、決まったパス下のものしか叩けない、など制限は多いけど、ある程度のテストになら十分使える。&lt;br /&gt;&lt;br /&gt;pythonの標準配布ライブラリがここまでそろっているから、あとはこんなふうに：&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from BaseHTTPServer import HTTPServer&lt;br /&gt;from SimpleHTTPServer import SimpleHTTPRequestHandler&lt;br /&gt;HTTPServer(('', 8000), SimpleHTTPRequestHandler).serve_forever()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;コードを書いて実行するだけで、http://127.0.0.1:8000/ から見られるWebサーバーが立ち上がるようになったわけ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5865816286213316823?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5865816286213316823/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5865816286213316823' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5865816286213316823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5865816286213316823'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/pythonhttp.html' title='pythonの付属HTTPサーバーを読む'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-426127085354647491</id><published>2008-07-17T00:43:00.004+09:00</published><updated>2008-07-17T01:05:07.563+09:00</updated><title type='text'>pythonサンプル・ROT13</title><content type='html'>ROT13ってのはごく単純な暗号アルゴリズムで、AをN、BをOとかそんな入れ替えだけを行って文章をわかりにくくする方法。シーザー暗号とかともいう。&lt;br /&gt;&lt;br /&gt;pythonの対話プロンプト上で、import thisと叩くと、the Zen of Pythonっていうタイトルの変な詩が表示される。オマケ機能。&lt;br /&gt;thisモジュールを読んでみたら、詩そのものはこのROT13で簡易暗号化されて格納されていた。同モジュールにはその復号ルーチンも含まれていて、短いサンプルが得られた。これを参考に関数としてちょっとだけ書き直すと、&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;d = {}&lt;br /&gt;for c in (65, 97):&lt;br /&gt;    for i in range(26):&lt;br /&gt;        d[chr(i+c)] = chr((i+13) % 26 + c)&lt;br /&gt;def rot13(s):&lt;br /&gt;    return "".join([d.get(c,c) for c in s])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;って感じ。dが翻字用辞書で、ここでは手を抜いてグローバル変数としている。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;これを使ってみるテスト&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; rot13("I don't know why you say good-bye. I say hello.")&lt;br /&gt;"V qba'g xabj jul lbh fnl tbbq-olr. V fnl uryyb."&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; rot13("V qba'g xabj jul lbh fnl tbbq-olr. V fnl uryyb.")&lt;br /&gt;"I don't know why you say good-bye. I say hello."&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;暗号化と復号が全く同じルーチンでできますね。&lt;br /&gt;&lt;br /&gt;まあ、最初からencodeを使ってもよかったんだけど。こんなコーデックがあるのねえ。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; "I don't know why you say good-bye. I say hello.".encode('rot_13')&lt;br /&gt;"V qba'g xabj jul lbh fnl tbbq-olr. V fnl uryyb."&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; "V qba'g xabj jul lbh fnl tbbq-olr. V fnl uryyb.".decode('rot_13')&lt;br /&gt;u"I don't know why you say good-bye. I say hello."&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-426127085354647491?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/426127085354647491/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=426127085354647491' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/426127085354647491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/426127085354647491'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/pythonrot13.html' title='pythonサンプル・ROT13'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7090127577846061322</id><published>2008-07-14T21:39:00.002+09:00</published><updated>2008-07-14T21:44:36.352+09:00</updated><title type='text'>pythonサンプル・ファイル削除</title><content type='html'>ファイル削除は、osモジュールにある。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import os&lt;br /&gt;os.remove(r'c:\doko\zo\no\file.txt')&lt;br /&gt;# os.unlink(r'c:\doko\zo\no\file.txt')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;removeとunlinkは全く同じ。UN*X的にはunlinkが分かりやすいのだけど、そうでないユーザーにも安心して使えるように、より直感的なremoveという別名も用意してくれたのだろう。か?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7090127577846061322?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7090127577846061322/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7090127577846061322' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7090127577846061322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7090127577846061322'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python_14.html' title='pythonサンプル・ファイル削除'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-6967221089008253840</id><published>2008-07-10T22:28:00.002+09:00</published><updated>2008-07-10T22:36:33.636+09:00</updated><title type='text'>pythonでアップロード</title><content type='html'>アップローダじゃなくて、今度はアップローダに「アップロード」するというサンプル。つまりHTTPクライアント側。&lt;br /&gt;&lt;br /&gt;ファイルをアップロードするときの動作をリクエストヘッダからPOSTデータ本体からみんな手作りして、あとはサーバーへのコネクションに流し込む。&lt;br /&gt;下のサンプルではあまり大きすぎるファイルはStringIO用のメモリを圧迫して失敗しそうな気がするけど、まあある程度までなら大丈夫、だった。&lt;br /&gt;ここではupfileというファイル欄とownerというテキスト欄を持ったフォームの内容を、http://doko.zo/no/uploader.cgiというアップローダのURLに送っている。&lt;br /&gt;&lt;br /&gt;aとかいうメソッド名がいいかげんだなあ。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!python&lt;br /&gt;# -*- encoding: utf-8 -*-&lt;br /&gt;&lt;br /&gt;import urllib2&lt;br /&gt;import random&lt;br /&gt;import os.path&lt;br /&gt;import StringIO&lt;br /&gt;&lt;br /&gt;boundary = '-----------48923489478932'&lt;br /&gt;&lt;br /&gt;def a(filename):&lt;br /&gt;    s = StringIO.StringIO()&lt;br /&gt;    s.write('--%s\r\n' % boundary)&lt;br /&gt;    s.write('Content-Disposition: form-data; name="upfile"; filename="%s"\r\n' % (os.path.split(filename)[1]))&lt;br /&gt;    s.write('Content-Type: application/octet-stream\r\n')&lt;br /&gt;    s.write('\r\n')&lt;br /&gt;    f = open(filename, 'rb').read()&lt;br /&gt;    s.write(f)&lt;br /&gt;    s.write('\r\n')&lt;br /&gt;    s.write('--%s\r\n' % boundary)&lt;br /&gt;    s.write('Content-Disposition: form-data; name="owner"\r\n')&lt;br /&gt;    s.write('\r\n')&lt;br /&gt;    s.write('dare\r\n')&lt;br /&gt;    s.write('--%s--\r\n' % boundary)&lt;br /&gt;    return s.getvalue()&lt;br /&gt;&lt;br /&gt;d = a(r'c:\nantyara.jpg')&lt;br /&gt;req = urllib2.Request('http://doko.zo/no/uploader.cgi', d)&lt;br /&gt;req.add_header('Content-Type', 'multipart/form-data;  boundary=%s' % boundary)&lt;br /&gt;print urllib2.urlopen(req).read()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-6967221089008253840?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/6967221089008253840/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=6967221089008253840' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6967221089008253840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6967221089008253840'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python_10.html' title='pythonでアップロード'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8076886649302802261</id><published>2008-07-08T22:47:00.003+09:00</published><updated>2008-07-09T11:40:09.976+09:00</updated><title type='text'>pythonでアップローダ・Webサーバ付</title><content type='html'>サーバースクリプトを下のように書いて実行する。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import CGIHTTPServer&lt;br /&gt;CGIHTTPServer.test()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;次に、同じディレクトリに uploader.html というファイルを作って下のような内容を書く。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;アップロード&amp;lt;br&amp;gt;&lt;br /&gt;&amp;lt;form method="POST" action="/cgi-bin/up.py" ENCTYPE="multipart/form-data"&amp;gt;&lt;br /&gt;&amp;lt;input type="file" name="upfile"&amp;gt;&lt;br /&gt;&amp;lt;input type="submit"&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;最後に、同じディレクトリにcgi-binという名前のディレクトリを作って、その下にup.pyというCGIスクリプトを下のように書く。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!python&lt;br /&gt;# -*- encoding: utf-8 -*-&lt;br /&gt;&lt;br /&gt;from random import random&lt;br /&gt;import md5&lt;br /&gt;from datetime import time&lt;br /&gt;import cgi&lt;br /&gt;import cgitb; cgitb.enable()&lt;br /&gt;&lt;br /&gt;store_root = r'c:\work\store\'   #ここは環境にあわせて&lt;br /&gt;&lt;br /&gt;fields = cgi.FieldStorage()&lt;br /&gt;print 'Content-Type: text/plain\n'&lt;br /&gt;#cgi.print_environ()&lt;br /&gt;bitstream_id = str(int(md5.new(str(random())+str(time())).hexdigest(),16))&lt;br /&gt;&lt;br /&gt;try:&lt;br /&gt;    t = open(store_root+bitstream_id, 'wb')&lt;br /&gt;    while True:&lt;br /&gt;        chunk = fields["upfile"].file.read(100000)&lt;br /&gt;        if not chunk: break&lt;br /&gt;        t.write(chunk)&lt;br /&gt;    t.close()&lt;br /&gt;    #t.write(fields["upfile"].value)&lt;br /&gt;    t = open(store_root+bitstream_id, 'rb')&lt;br /&gt;    digest = md5.new(t.read()).hexdigest()&lt;br /&gt;    t.close()&lt;br /&gt;    t = open(store_root+bitstream_id+'.metadata', 'wb')&lt;br /&gt;    t.write(fields["upfile"].filename)&lt;br /&gt;    t.write('\n')&lt;br /&gt;    t.write(digest)&lt;br /&gt;    t.close()&lt;br /&gt;    print "OK\n%s\n%s" % (bitstream_id, digest)&lt;br /&gt;except:&lt;br /&gt;    print "NG"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これで、http://127.0.0.1/uploader.html からアップローダの動作を試すことができる。&lt;br /&gt;&lt;br /&gt;アップロードしたファイルはランダムな英数字の羅列のファイル名に変換されて格納されるが、同じ名前に .metadata とついたファイルが同時に生成されて、そこにはもとのファイル名とチェックサム(md5ハッシュ値)が記録される。&lt;br /&gt;&lt;br /&gt;到底堅牢なものとは言えないけど、それなりに動作する。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8076886649302802261?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8076886649302802261/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8076886649302802261' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8076886649302802261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8076886649302802261'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/pythonweb.html' title='pythonでアップローダ・Webサーバ付'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1791105528027458159</id><published>2008-07-07T22:55:00.002+09:00</published><updated>2008-07-07T22:58:28.913+09:00</updated><title type='text'>pygameでテトリス（と紛らわしいもの）</title><content type='html'>テトリスを作ってみたくなっていろいろいじくりはじめたが、脱線して変なデモになった。&lt;br /&gt;中央からランダムなテトリミノが回転しつつ噴水のようにほとばしるという、ワケわからないもの。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from random import randint&lt;br /&gt;import pygame&lt;br /&gt;import pygame.locals as C&lt;br /&gt;&lt;br /&gt;t = [ 'efghbfjnefghbfjn', 'abefabefabefabef', 'efgbbfjgefgjbfje',&lt;br /&gt;      'abfgbfeiabfgbfei', 'bfeiabfgbfeiabfg', 'efgkbfjiaefgbfjc',&lt;br /&gt;      'aefgbfjcefgkbfji']&lt;br /&gt;clr = [ 0xff00ff, 0xff8000, 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff]&lt;br /&gt;tet = []&lt;br /&gt;for i1 in t:&lt;br /&gt;    t2 = []&lt;br /&gt;    for i2 in xrange(4):&lt;br /&gt;        t3 = []&lt;br /&gt;        for k in i1[i2*4:i2*4+4]:&lt;br /&gt;            t = ord(k) - ord('a')&lt;br /&gt;            t3.append((t%4, t/4,))&lt;br /&gt;        t2.append(t3)&lt;br /&gt;    tet.append(t2)&lt;br /&gt;&lt;br /&gt;class Tetrimino(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self, ruler, kind, place, speed):&lt;br /&gt;        self.kind = kind&lt;br /&gt;        self.x, self.y = place&lt;br /&gt;        self.xx, self.yy = speed&lt;br /&gt;        self.iter = iter(self)&lt;br /&gt;        self.r = 0&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        rr = 0&lt;br /&gt;        while True:&lt;br /&gt;            rr = (rr+1) % 4&lt;br /&gt;            if rr == 0: self.r = (self.r+1) % 4&lt;br /&gt;            self.x += self.xx&lt;br /&gt;            self.y -= self.yy&lt;br /&gt;            if self.y &amp;gt; 560: break&lt;br /&gt;            self.yy -= 1&lt;br /&gt;            yield&lt;br /&gt;&lt;br /&gt;    def draw(self, surface):&lt;br /&gt;        for xd, yd in tet[self.kind][self.r]:&lt;br /&gt;            pygame.draw.rect(surface, clr[self.kind],&lt;br /&gt;                             (self.x+xd*16, self.y+yd*16-80, 15, 15), 0)&lt;br /&gt;&lt;br /&gt;class Gunner(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self, ruler, place, prob):&lt;br /&gt;        self.ruler = ruler&lt;br /&gt;        self.place = place&lt;br /&gt;        self.prob = prob&lt;br /&gt;        self.iter = iter(self)&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        while True:&lt;br /&gt;            if randint(0, 99) &amp;lt; self.prob:&lt;br /&gt;                speed = (randint(-15, 15), randint(5, 25))&lt;br /&gt;                self.ruler.t.append(Tetrimino(&lt;br /&gt;                    self.ruler, randint(0, 6), self.place, speed,))&lt;br /&gt;            yield&lt;br /&gt;&lt;br /&gt;class BackGround(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, ruler):&lt;br /&gt;        self.ruler = ruler&lt;br /&gt;        self.iter = iter(self)&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        while True: yield&lt;br /&gt;&lt;br /&gt;    def draw(self, surface):&lt;br /&gt;        surface.fill(0x003000)&lt;br /&gt;&lt;br /&gt;class GameRuler(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.t = []&lt;br /&gt;        self.t.append(BackGround(self))&lt;br /&gt;        self.t.append(Gunner(self, (320, 480), 26))&lt;br /&gt;        pygame.display.set_mode((640, 480))&lt;br /&gt;        self.surface = pygame.display.get_surface()&lt;br /&gt;        self.clock = pygame.time.Clock()&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        while True:&lt;br /&gt;            tt = []&lt;br /&gt;            for j in self.t:&lt;br /&gt;                try:&lt;br /&gt;                    j.iter.next()&lt;br /&gt;                    tt.append(j)&lt;br /&gt;                except StopIteration:&lt;br /&gt;                    continue&lt;br /&gt;                if hasattr(j, 'draw'): j.draw(self.surface)&lt;br /&gt;            self.t = tt&lt;br /&gt;            yield&lt;br /&gt;            # adjust timing ...&lt;br /&gt;            pygame.display.flip()&lt;br /&gt;            if pygame.event.poll().type == C.QUIT:&lt;br /&gt;                break&lt;br /&gt;            self.clock.tick(30)&lt;br /&gt;&lt;br /&gt;pygame.init()&lt;br /&gt;r = GameRuler()&lt;br /&gt;for i in r: pass&lt;br /&gt;pygame.quit()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1791105528027458159?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1791105528027458159/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1791105528027458159' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1791105528027458159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1791105528027458159'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/pygame_07.html' title='pygameでテトリス（と紛らわしいもの）'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7694630969175168400</id><published>2008-07-06T21:40:00.003+09:00</published><updated>2008-07-06T21:45:36.499+09:00</updated><title type='text'>pygameでお絵かきツール</title><content type='html'>pygameをもうちょっといじってみようと、今度は簡単なお絵かきツールを。&lt;br /&gt;といったって、マウスドラックで線が書けるというだけのシロモノだけど。&lt;br /&gt;しかも、前回のエントリを変な感じに再利用している。（再利用を目指しているともいえるけど、まだ不器用な感じ）&lt;br /&gt;&lt;br /&gt;pygameはマウスイベントを受け取るのも簡単だなあという例。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import pygame&lt;br /&gt;import pygame.locals as C&lt;br /&gt;&lt;br /&gt;class MouseSenser(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, ruler):&lt;br /&gt;        self.ruler = ruler&lt;br /&gt;        self.iter = self.__iter__()&lt;br /&gt;        self.prevpos = (0, 0)&lt;br /&gt;        self.drawing = False&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        while True:&lt;br /&gt;            e = self.ruler.event&lt;br /&gt;            if e.type != C.MOUSEMOTION:&lt;br /&gt;                yield&lt;br /&gt;                continue&lt;br /&gt;            self.pos = e.pos&lt;br /&gt;            self.pressed = e.buttons[0]&lt;br /&gt;            if self.pressed:&lt;br /&gt;                if self.drawing:&lt;br /&gt;                    self.line = (self.prevpos, self.pos, )&lt;br /&gt;                    self.prevpos = self.pos&lt;br /&gt;                else:&lt;br /&gt;                    self.prevpos = self.pos&lt;br /&gt;                    self.drawing = True&lt;br /&gt;                    self.line = (self.pos, self.pos, )&lt;br /&gt;            else:&lt;br /&gt;                self.drawing = False&lt;br /&gt;            yield&lt;br /&gt;&lt;br /&gt;    def draw(self, surface):&lt;br /&gt;        if self.drawing:&lt;br /&gt;            pygame.draw.line(surface, 0xffffff, self.line[0], self.line[1], 2)&lt;br /&gt;&lt;br /&gt;class GameRuler(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.t = []&lt;br /&gt;        self.t.append(MouseSenser(self))&lt;br /&gt;        pygame.display.set_mode((640, 480))&lt;br /&gt;        self.surface = pygame.display.get_surface()&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        clock = pygame.time.Clock()&lt;br /&gt;        while True:&lt;br /&gt;            while True:&lt;br /&gt;                e = pygame.event.poll()&lt;br /&gt;                if e.type == C.QUIT: raise StopIteration&lt;br /&gt;                if e.type == C.NOEVENT: break&lt;br /&gt;                self.event = e&lt;br /&gt;            tt = []&lt;br /&gt;            for j in self.t:&lt;br /&gt;                try:&lt;br /&gt;                    j.iter.next()&lt;br /&gt;                except StopIteration:&lt;br /&gt;                    continue&lt;br /&gt;                tt.append(j)&lt;br /&gt;                if hasattr(j, 'draw'): j.draw(self.surface)&lt;br /&gt;            self.t = tt&lt;br /&gt;            pygame.display.flip()&lt;br /&gt;            yield&lt;br /&gt;            clock.tick(30)&lt;br /&gt;&lt;br /&gt;pygame.init()&lt;br /&gt;r = GameRuler()&lt;br /&gt;for i in r: pass&lt;br /&gt;pygame.quit()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;こんな感じに描けるよ。マウス代わりにタブレットを使ったけど。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Zi6PKIg2V_I/SHC-LmmbcXI/AAAAAAAAAmo/zOoRpasmafU/s1600-h/mikkyo.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_Zi6PKIg2V_I/SHC-LmmbcXI/AAAAAAAAAmo/zOoRpasmafU/s320/mikkyo.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5219881074671972722" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7694630969175168400?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7694630969175168400/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7694630969175168400' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7694630969175168400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7694630969175168400'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/pygame.html' title='pygameでお絵かきツール'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Zi6PKIg2V_I/SHC-LmmbcXI/AAAAAAAAAmo/zOoRpasmafU/s72-c/mikkyo.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-6021985451337594359</id><published>2008-07-05T12:43:00.004+09:00</published><updated>2008-07-05T14:49:27.834+09:00</updated><title type='text'>pythonサンプル・pygameデモ</title><content type='html'>pygameを使ったちょっとしたデモ。&lt;br /&gt;左下と右下に配置された見えない高射砲？がランダムに弾丸を発射し、空中で破裂する。&lt;br /&gt;&lt;br /&gt;yieldを多用してみたのが今回の特徴。yieldはイテレータ/ジェネレータを実現するための命令で、ここではイテレータから値をひとつ読み出すと「副作用で」ゲームが一コマ進行する、という変なものになっている。&lt;br /&gt;&lt;br /&gt;なんでこんなやりかたで作ったかというと、単にやってみたかったから。yieldを覚えてからpythonの楽しさは倍増です。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from random import randint&lt;br /&gt;import pygame&lt;br /&gt;import pygame.locals as C&lt;br /&gt;&lt;br /&gt;class Bullet(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self, ruler, p_from, p_target):&lt;br /&gt;        self.ruler = ruler&lt;br /&gt;        self.p_from = p_from&lt;br /&gt;        self.p_current = p_from&lt;br /&gt;        self.p_target = p_target&lt;br /&gt;        self.iter = self.__iter__()&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        self.status = 'flying'&lt;br /&gt;        for s in xrange(60):&lt;br /&gt;            x, y = self.p_from&lt;br /&gt;            tx, ty = self.p_target&lt;br /&gt;            self.p_prev = self.p_current&lt;br /&gt;            self.p_current = x+(tx-x)*s/60, y+(ty-y)*s/60&lt;br /&gt;            yield&lt;br /&gt;        self.status = 'exploding'&lt;br /&gt;        self.p_current = self.p_target&lt;br /&gt;        for s in xrange(63):&lt;br /&gt;            self.blast = s+1&lt;br /&gt;            yield&lt;br /&gt;&lt;br /&gt;    def draw(self, surface):&lt;br /&gt;        if self.status == 'flying':&lt;br /&gt;            pygame.draw.line(surface, 0, self.p_prev, self.p_current)&lt;br /&gt;        if self.status == 'exploding':&lt;br /&gt;            c = (self.blast*4,self.blast*4, 255)&lt;br /&gt;            pygame.draw.circle(surface, c, self.p_current, self.blast, 1)&lt;br /&gt;&lt;br /&gt;class Gunner(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self, ruler, place, prob):&lt;br /&gt;        self.ruler = ruler&lt;br /&gt;        self.place = place&lt;br /&gt;        self.prob = prob&lt;br /&gt;        self.iter = self.__iter__()&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        while True:&lt;br /&gt;            if randint(0, 99) &amp;lt; self.prob:&lt;br /&gt;                target = randint(0, 639), randint(0, 400)&lt;br /&gt;                self.ruler.t.append(Bullet(self.ruler, self.place, target))&lt;br /&gt;            yield&lt;br /&gt;&lt;br /&gt;class GameRuler(object):&lt;br /&gt;    &lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.t = []&lt;br /&gt;        self.t.append(Gunner(self, (0, 480), 16))&lt;br /&gt;        self.t.append(Gunner(self, (640, 480), 10))&lt;br /&gt;        pygame.display.set_mode((640, 480))&lt;br /&gt;        self.surface = pygame.display.get_surface()&lt;br /&gt;        self.clock = pygame.time.Clock()&lt;br /&gt;&lt;br /&gt;    def __iter__(self):&lt;br /&gt;        while True:&lt;br /&gt;            self.surface.fill(0xffffff)&lt;br /&gt;            tt = []&lt;br /&gt;            for j in self.t:&lt;br /&gt;                try:&lt;br /&gt;                    j.iter.next()&lt;br /&gt;                    tt.append(j)&lt;br /&gt;                except StopIteration:&lt;br /&gt;                    pass&lt;br /&gt;                if hasattr(j, 'draw'): j.draw(self.surface)&lt;br /&gt;            self.t = tt&lt;br /&gt;            yield&lt;br /&gt;            # adjust timing ...&lt;br /&gt;            pygame.display.flip()&lt;br /&gt;            if pygame.event.poll().type == C.QUIT:&lt;br /&gt;                break&lt;br /&gt;            self.clock.tick(30)&lt;br /&gt;&lt;br /&gt;pygame.init()&lt;br /&gt;r = GameRuler()&lt;br /&gt;for i in r: pass&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-6021985451337594359?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/6021985451337594359/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=6021985451337594359' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6021985451337594359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6021985451337594359'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/pythonpygame.html' title='pythonサンプル・pygameデモ'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5060655226880074407</id><published>2008-07-03T21:24:00.003+09:00</published><updated>2008-07-03T21:37:00.071+09:00</updated><title type='text'>pythonで日付を扱う</title><content type='html'>日付を扱う方法について度忘れすることもあるので、pythonの対話プロンプトからいろいろ試した結果を貼り付けて今後のメモにする。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# 日付を扱うときに必要なモジュールをインポート&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import datetime&lt;br /&gt;# 今日&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; datetime.date.today()&lt;br /&gt;datetime.date(2008, 7, 3)&lt;br /&gt;# 今日＋現在時刻&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; datetime.datetime.now()&lt;br /&gt;datetime.datetime(2008, 7, 3, 21, 11, 44, 15000)&lt;br /&gt;# dateオブジェクトの文字列表現&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a = datetime.date.today()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a.__str__()&lt;br /&gt;'2008-07-03'&lt;br /&gt;# __str__は、printするときにどう表示されるかを定義する。だから下のように。&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print a&lt;br /&gt;2008-07-03&lt;br /&gt;# dateオブジェクトをその他の形式にフォーマットする&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a.strftime('%B %d, %Y')&lt;br /&gt;'July 03, 2008'&lt;br /&gt;# dateオブジェクトのn日後（負数ならn日前）の日付を出す&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a + datetime.timedelta(1)&lt;br /&gt;datetime.date(2008, 7, 4)&lt;br /&gt;# 100日後なんかでも問題ない&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; a + datetime.timedelta(100)&lt;br /&gt;datetime.date(2008, 10, 11)&lt;br /&gt;# 年、月、日をそれぞれ数値から受け取ってdateオブジェクトを構築&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; datetime.date(2008, 10, 2).__str__()&lt;br /&gt;'2008-10-02'&lt;br /&gt;# フォーマットされた日付文字列を解析してdateオブジェクトを作る&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; datetime.datetime.strptime('2008.10.12', '%Y.%m.%d')&lt;br /&gt;datetime.datetime(2008, 10, 12, 0, 0)&lt;br /&gt;#&lt;br /&gt;# 次はcalendarモジュール。python2.5から標準配布みたい&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import calendar&lt;br /&gt;# カレンダー機能は、いったんCalendarオブジェクトを作ってから使う&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; c = calendar.Calendar()&lt;br /&gt;# 年月を指定して、日を全部表示する&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; c.itermonthdates(2008, 9)&lt;br /&gt;&amp;lt;generator object at 0x011BEF80&amp;gt;&lt;br /&gt;# 上のままだと、ジェネレータ（イテレータ）だけ帰ってくる。なので&lt;br /&gt;# リスト内包なんかで展開して表示してみる&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; [i for i in c.itermonthdates(2008, 9)]&lt;br /&gt;[datetime.date(2008, 9, 1), datetime.date(2008, 9, 2), datetie&lt;br /&gt;.date(2008, 9, 3), datetime.date(2008, 9, 4), datetime.date(20&lt;br /&gt;08, 9, 5), datetime.date(2008, 9, 6), datetime.date(2008, 9, 7)&lt;br /&gt;, datetime.date(2008, 9, 8), datetime.date(2008, 9, 9), dateti&lt;br /&gt;me.date(2008, 9, 10), datetime.date(2008, 9, 11), datetime.dat&lt;br /&gt;e(2008, 9, 12), datetime.date(2008, 9, 13), datetime.date(2008&lt;br /&gt;, 9, 14), datetime.date(2008, 9, 15), datetime.date(2008, 9, 1&lt;br /&gt;6), datetime.date(2008, 9, 17), datetime.date(2008, 9, 18), da&lt;br /&gt;tetime.date(2008, 9, 19), datetime.date(2008, 9, 20), datetime&lt;br /&gt;.date(2008, 9, 21), datetime.date(2008, 9, 22), datetime.date(&lt;br /&gt;2008, 9, 23), datetime.date(2008, 9, 24), datetime.date(2008, &lt;br /&gt;9, 25), datetime.date(2008, 9, 26), datetime.date(2008, 9, 27)&lt;br /&gt;, datetime.date(2008, 9, 28), datetime.date(2008, 9, 29), date&lt;br /&gt;time.date(2008, 9, 30), datetime.date(2008, 10, 1), datetime.d&lt;br /&gt;ate(2008, 10, 2), datetime.date(2008, 10, 3), datetime.date(20&lt;br /&gt;08, 10, 4), datetime.date(2008, 10, 5)]&lt;br /&gt;# 上の表示結果は、9月の日付だけでなくて、8月と10月がちょっとくっ&lt;br /&gt;# ついているのに気づく。これはカレンダーを表示しやすいように、&lt;br /&gt;# 一週間単位にそろえてデータを作ってくれるため。これが余計なら、&lt;br /&gt;# もらったあとで省いて使えばよい。&lt;br /&gt;#&lt;br /&gt;# 今度は年間カレンダーを…&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; c.yeardatescalendar(2009)&lt;br /&gt;（この結果を引用するのは省略します。やってみたらわかる。どっさり）&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5060655226880074407?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5060655226880074407/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5060655226880074407' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5060655226880074407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5060655226880074407'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python_03.html' title='pythonで日付を扱う'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-6133195330140253524</id><published>2008-07-02T22:13:00.003+09:00</published><updated>2008-07-02T22:45:45.873+09:00</updated><title type='text'>pythonサンプル・宿泊予約管理</title><content type='html'>全く役に立つバージョンではないけど、さしあたってはやりかたの取っ掛かりだけを。&lt;br /&gt;&lt;br /&gt;python2.5からはsqlite3モジュールが標準配布になっているので、これを使ってデータベース管理をしてみることを考える。ここでは手始めに宿泊予約管理みたいなものがどうやって実現できるかを示す。&lt;br /&gt;&lt;br /&gt;sqlite3は、ファイルベースの簡易RDBライブラリ。データベース管理のためのサービスプロセスを立ち上げなくてもいいところが手軽でよい。&lt;br /&gt;&lt;br /&gt;まず、初期データを作る。下のようなスクリプトを書いて実行すると&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sqlite3&lt;br /&gt;&lt;br /&gt;c = sqlite3.connect('testdb')&lt;br /&gt;c.execute('create table heya (date text, vacant int, reserved int)')&lt;br /&gt;for i in xrange(1, 32):&lt;br /&gt;    c.execute("insert into heya values (?, ? ,?)", ("2008-07-%02d" % i, 10, 0))&lt;br /&gt;c.commit()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;スクリプトを置いたディレクトリの下に、testdbというファイルができあがる。これがデータベース。&lt;br /&gt;最初から2008年7月の予約台帳(heyaテーブル)ができている。vacant(空き室)は10、reserved(予約数)は0という初期値で。&lt;br /&gt;&lt;br /&gt;※データファイルを簡単に眺めるために、&lt;br /&gt;&lt;a href="http://sqlitebrowser.sourceforge.net/index.html"&gt;http://sqlitebrowser.sourceforge.net/index.html&lt;/a&gt;&lt;br /&gt;みたいなツールを使うとお手軽です。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;そしたら次は、下のような予約入力システム(?)のスクリプトを同ディレクトリに作成する。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sqlite3&lt;br /&gt;&lt;br /&gt;db = sqlite3.connect('testdb')&lt;br /&gt;&lt;br /&gt;class Yoyaku(object):&lt;br /&gt;    def __init__(self, dates, num=1):&lt;br /&gt;        self.dates = dates&lt;br /&gt;        self.num = num&lt;br /&gt;        self.status = 'unverified'&lt;br /&gt;&lt;br /&gt;    def can_reserve(self):&lt;br /&gt;        for i in self.dates:&lt;br /&gt;            r = [j for j in db.execute('select vacant from heya where date=?', [i])]&lt;br /&gt;            print r&lt;br /&gt;            if len(r) == 0: return False&lt;br /&gt;            if r[0][0] &lt; self.num: return False&lt;br /&gt;        self.status = 'verified'&lt;br /&gt;        return True&lt;br /&gt;&lt;br /&gt;    def do_reserve(self):&lt;br /&gt;        if self.status == 'finished':&lt;br /&gt;            print "finished"&lt;br /&gt;            return&lt;br /&gt;        if self.status != 'verified':&lt;br /&gt;            print "not verified"&lt;br /&gt;            return&lt;br /&gt;        for i in self.dates:&lt;br /&gt;            db.execute(&lt;br /&gt;                'update heya set vacant=vacant-?, reserved=reserved+? where date=?', (self.num, self.num, i)&lt;br /&gt;                )&lt;br /&gt;        db.commit()&lt;br /&gt;        self.status = 'finished'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;このスクリプトはダブルクリックなんかで実行するとすぐ終わってしまって役に立たないので、IDLEみたいな環境から実行して、実行後もpythonのプロンプトが残るようにしながら実行すること。&lt;br /&gt;&lt;br /&gt;そしたら順に下のように命令を叩いて、動作を確認してゆく。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y1 = Yoyaku(['2008-07-01'], 3)  -----7月1日に3部屋予約&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y1.can_reserve()  -----できますか?&lt;br /&gt;[(10,)]&lt;br /&gt;True  ----- オッケー&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y1.do_reserve()  -----じゃあ予約確定&lt;br /&gt;OK.  ----- オッケー&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y1.do_reserve()  -----もういちど予約確定?&lt;br /&gt;NG. finished  ----- もう済んでるよ&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y2 = Yoyaku(['2008-07-01'], 8)  -----7月1日に8部屋予約&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y2.can_reserve()  -----できますか?&lt;br /&gt;[(7,)]&lt;br /&gt;False  ----- できないッス（空き部屋はあと7つだから）&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y2.do_reserve()  -----ええい、予約確定だ&lt;br /&gt;NG. not verified  ----- だからできないって&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y3 = Yoyaku(['2008-07-01', '2008-07-02', '2008-07-03'], 2)&lt;br /&gt;     ----- 7月1日、2日、3日と連続で2部屋予約&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y3.do_reserve()  -----予約確定!&lt;br /&gt;NG. not verified  -----まだ確認できてないよ&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y3.can_reserve()  -----そうか、じゃあ確認&lt;br /&gt;[(7,)]&lt;br /&gt;[(10,)]&lt;br /&gt;[(10,)]&lt;br /&gt;True  -----部屋取れるよ&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; y3.do_reserve()  -----改めて予約確定!&lt;br /&gt;OK.  -----オッケー&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;最後にツールを使ってテーブルの中身を眺めて、確かに台帳が更新されていることを確認する。&lt;br /&gt;&lt;br /&gt;あとは予約者の記録とか、部屋の種類を増やすとか、こんなコマンド叩かないで済むようにGUIをつけるとかWebインターフェースをつけるとか、そんな拡張をしながら本物のシステムっぽく育っていく、んじゃないかな。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-6133195330140253524?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/6133195330140253524/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=6133195330140253524' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6133195330140253524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6133195330140253524'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python_02.html' title='pythonサンプル・宿泊予約管理'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5802003102953110032</id><published>2008-07-01T22:05:00.003+09:00</published><updated>2008-07-01T22:22:38.834+09:00</updated><title type='text'>pythonサンプル・数独</title><content type='html'>数独を解くスクリプト。（数独はニコリの登録商標です）&lt;br /&gt;途中でboard配列を作っている文字列を変えれば、他の問題も解ける。81文字で、9x9マスの左上から右下の状態を順に書いていくだけ。0は未定マスという意味。&lt;br /&gt;&lt;br /&gt;setオブジェクトを途中で使っている。これはpython2.4以降実装されたもののようなので注意。setは使いどころによっては便利なもので、順番を持たない、重複しない値の集合。辞書のキー部分だけみたいなものといえる。片っ端から値をsetに放り込んでいくと、ユニーク値の集合が得られる。あと、setどうしで差集合をとることも簡単にできる。数独を解くのにちょうど便利だった。&lt;br /&gt;&lt;br /&gt;パズルを解くアルゴリズムとして、check_my_number_can_fixedメソッドとexclude_fixed_number_from_neighborsメソッドを書いてみた。前者は、あるマスの数字が一種類に確定できそうか調べるもの。後者は、数字が確定できている時に、周り8マスと縦8マス横8マスの影響範囲にはもうその数字が入りっこないことを表現するもの。これらを交互に実行して、少しずつパズルを解いていこうという意図。&lt;br /&gt;&lt;br /&gt;この程度のスクリプトだと、難問は結構途中でギブアップしてしまうようだ。でも途中までは解くので、あとは勘で適当なマスの数字を決め打って正常に解けるか試す、という方法を繰り返せば、まあ解決支援ツールとしてくらいの使い道はある。&lt;br /&gt;&lt;br /&gt;Wikipediaの「数独」の記事に出ていたサンプルくらいだと、楽に解けた。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import copy&lt;br /&gt;&lt;br /&gt;def list_neighbor(pos):&lt;br /&gt;    s = [[],[],[]]&lt;br /&gt;    for i in xrange(9): s[0].append((pos%9)+i*9) #tate&lt;br /&gt;    for i in xrange(9): s[1].append(int(pos/9)*9+i) #yoko&lt;br /&gt;    t = int(pos/27)*27 + int((pos%9)/3)*3 #block&lt;br /&gt;    for i in (0,1,2,9,10,11,18,19,20): s[2].append(t+i)&lt;br /&gt;    s[0].remove(pos) #remove myself&lt;br /&gt;    s[1].remove(pos)&lt;br /&gt;    s[2].remove(pos)&lt;br /&gt;    return s&lt;br /&gt;&lt;br /&gt;def dump():&lt;br /&gt;    for i in xrange(9):&lt;br /&gt;        for j in cand_table[i*9:i*9+9]:&lt;br /&gt;            print "%s," % " or ".join(map(str, j)),&lt;br /&gt;        print&lt;br /&gt;    print "-" * 72&lt;br /&gt;&lt;br /&gt;def check_my_number_can_fixed():&lt;br /&gt;    for i in xrange(len(cand_table)):&lt;br /&gt;        for j in neighbor_table[i]:&lt;br /&gt;            if len(cand_table[i]) &amp;gt; 1:&lt;br /&gt;                s = set(cand_table[i])&lt;br /&gt;                for jj in j:&lt;br /&gt;                    s.difference_update(cand_table[jj])&lt;br /&gt;                s = list(s)&lt;br /&gt;                if len(s) == 1:&lt;br /&gt;                    cand_table[i] = s&lt;br /&gt;                    break&lt;br /&gt;&lt;br /&gt;def exclude_fixed_number_from_neighbors():&lt;br /&gt;    for i in xrange(len(cand_table)):&lt;br /&gt;        if len(cand_table[i]) == 1:&lt;br /&gt;            for j in neighbor_table[i]:&lt;br /&gt;                for jj in j:&lt;br /&gt;                    try:&lt;br /&gt;                        cand_table[jj].remove(cand_table[i][0])&lt;br /&gt;                    except:&lt;br /&gt;                        pass&lt;br /&gt;&lt;br /&gt;board = [int(i) for i in&lt;br /&gt;         '530070000600195000098000060800060003400803001700020006060000280000419005000080079']&lt;br /&gt;&lt;br /&gt;cand_table = []&lt;br /&gt;for i in board:&lt;br /&gt;    if i == 0:&lt;br /&gt;        cand_table.append(range(1, 10))&lt;br /&gt;    else:&lt;br /&gt;        cand_table.append([i])&lt;br /&gt;neighbor_table = [list_neighbor(i) for i in xrange(len(board))]&lt;br /&gt;while 1:&lt;br /&gt;    r = copy.deepcopy(cand_table)&lt;br /&gt;    dump()&lt;br /&gt;    check_my_number_can_fixed()&lt;br /&gt;    dump()&lt;br /&gt;    exclude_fixed_number_from_neighbors()&lt;br /&gt;    if r == cand_table:&lt;br /&gt;        print "no more change... maybe SOLVED or GIVEUP"&lt;br /&gt;        break&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5802003102953110032?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5802003102953110032/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5802003102953110032' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5802003102953110032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5802003102953110032'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/07/python.html' title='pythonサンプル・数独'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-4548099483332068292</id><published>2008-06-30T20:38:00.003+09:00</published><updated>2008-06-30T21:25:31.279+09:00</updated><title type='text'>pythonサンプル・オセロ</title><content type='html'>オセロゲームをコンピュータ同士が延々とやりつづけるというデモ用スクリプト。&lt;br /&gt;&lt;br /&gt;think_choiceが、どこにコマを置くかを考えるという部分。8x8で全部で64コマを調べて、どこに置くと一番コマが取れるかを考えている。いつも同じ結果ではアレなので、ちょっとランダムさも混ぜている。&lt;br /&gt;&lt;br /&gt;双方とも置く場所がなくなったら一番終了、コマの数を清算してから次のゲームに移る。&lt;br /&gt;&lt;br /&gt;あまりに早くて追いきれない場合は、#sys.stdin.readline() のコメントをはずせば、一手ごとにEnterキーをを押して進むようになる。&lt;br /&gt;&lt;br /&gt;ひとつ手が進むたびにdisplay_board(board)を呼んで盤の状態を表示させているが、ここをコメント化（2箇所）すると、途中経過をすっ飛ばしてすごい勢いで勝敗だけを表示し始める。ほうっておくと100番でも1000番でもコンピュータ同士で勝手にオセロし続ける。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sys&lt;br /&gt;from random import randint&lt;br /&gt;&lt;br /&gt;def display_board(board):&lt;br /&gt;    for i in xrange(8):&lt;br /&gt;        for j in board[i*8:i*8+8]: print ('.', 'O', 'X')[j],&lt;br /&gt;        print&lt;br /&gt;    print&lt;br /&gt;&lt;br /&gt;def think_choice(board, me, opp):&lt;br /&gt;    choice, result = None, []&lt;br /&gt;    for pos in xrange(64):&lt;br /&gt;        if board[pos] != 0: continue&lt;br /&gt;        x = pos % 8; y = pos / 8&lt;br /&gt;        cand = []&lt;br /&gt;        # scan all directions&lt;br /&gt;        for xx, yy in ((0,-1),(1,-1),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1)):&lt;br /&gt;            cand_tmp = []&lt;br /&gt;            distance = 1&lt;br /&gt;            while True:&lt;br /&gt;                xt = x+xx*distance ; yt = y+yy*distance&lt;br /&gt;                if xt &amp;gt; 7 or xt &amp;lt; 0 or yt &amp;gt; 7 or yt &amp;lt; 0: break&lt;br /&gt;                p = yt*8 + xt&lt;br /&gt;                if board[p] == opp: #add candidate&lt;br /&gt;                    cand_tmp.append(p)&lt;br /&gt;                    distance += 1&lt;br /&gt;                    continue&lt;br /&gt;                if board[p] == me and cand_tmp: #fix candidate&lt;br /&gt;                    cand.extend(cand_tmp)&lt;br /&gt;                    break&lt;br /&gt;                break&lt;br /&gt;            if not cand: continue&lt;br /&gt;            # nearly random strategy :)&lt;br /&gt;            if pos in (0, 7, 56, 63): return pos, cand # sumikko!&lt;br /&gt;            if len(cand)+randint(0, 1) &amp;gt; len(result):&lt;br /&gt;                choice, result = pos, cand&lt;br /&gt;    return choice, result&lt;br /&gt;&lt;br /&gt;def play_othello():&lt;br /&gt;    board = [&lt;br /&gt;    0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 1, 2, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 2, 1, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;    0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;    ]&lt;br /&gt;    display_board(board)&lt;br /&gt;    player1, player2 = 1, 2&lt;br /&gt;    r = []&lt;br /&gt;    while 1:&lt;br /&gt;        choice, result = think_choice(board, me=player1, opp=player2)&lt;br /&gt;        if result:&lt;br /&gt;            board[choice] = player1&lt;br /&gt;            for i in result: board[i] = player1&lt;br /&gt;        if not (r or result): break&lt;br /&gt;        r = result&lt;br /&gt;        display_board(board)&lt;br /&gt;        player1, player2 = player2, player1&lt;br /&gt;        #sys.stdin.readline()&lt;br /&gt;    print "%s %s" % ("O" * board.count(1), "X" * board.count(2))&lt;br /&gt;&lt;br /&gt;while 1: play_othello()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-4548099483332068292?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/4548099483332068292/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=4548099483332068292' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4548099483332068292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4548099483332068292'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python_30.html' title='pythonサンプル・オセロ'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-6570837581683356933</id><published>2008-06-29T13:21:00.004+09:00</published><updated>2008-06-29T13:45:23.314+09:00</updated><title type='text'>pythonでお絵かきロジック(未完)</title><content type='html'>気ままにコーディングをしているうちに、お絵かきロジックを解くプログラム、のフレームワークみたいなものになってきた。&lt;br /&gt;&lt;br /&gt;IllustLogicクラス自身はパズルを解くわけではなく、肝心の部分は外部の関数に任せてしまう。ここではコンストラクタが受け取るfunc引数がそれ。&lt;br /&gt;お絵かきロジックは、よく観察するとたくさんの小さなパズルに分かれるように見える。縦でも横でも、一度にやるべきパズルは一行分の細長いところだけだ。なので、funcにはそれを任せることにした。&lt;br /&gt;&lt;br /&gt;コンストラクタは、パズルの問題そのものも受け取る。rowhintとcolhintがそれ。各行、各列のヒントの数字を「配列の配列」として渡しているだけ。&lt;br /&gt;&lt;br /&gt;あとは、サンプルで書いたmy_logicをちゃんと書けば、パズル全体が解けるはず…まだやってないけど。今のmy_logicは、デタラメ。hintに一行分のヒント、artに一行分の配列が入ってくるので、それらを手がかりに新しく配列を作って返せばよい。0は未定、1は黒に決定、2は空白に決定、ということにした。マジックナンバーでかっこ悪いけど。&lt;br /&gt;&lt;br /&gt;あと、try_solveメソッドはパズルが完全に解けるか詰まるかするまで黙り込んでしまうので、あまりよくない。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class IllustLogic(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, func, rowhint, colhint):&lt;br /&gt;        self.line_processor = func&lt;br /&gt;        self.rowhint = rowhint&lt;br /&gt;        self.colhint = colhint&lt;br /&gt;        self.height = len(self.rowhint)&lt;br /&gt;        self.width = len(self.colhint)&lt;br /&gt;        self.board = [0 for i in xrange(self.width * self.height)]&lt;br /&gt;        self.todo = set()&lt;br /&gt;        for i in xrange(self.height): self.todo.add(('row', i))&lt;br /&gt;        for i in xrange(self.width): self.todo.add(('col', i))&lt;br /&gt;&lt;br /&gt;    def work_a_line(self, d, num):&lt;br /&gt;        if d == 'col':&lt;br /&gt;            poss = [num + self.width * i for i in xrange(self.height)]&lt;br /&gt;            hint = self.colhint[num]&lt;br /&gt;        else: #'row'&lt;br /&gt;            poss = [self.width * num + i for i in xrange(self.width)]&lt;br /&gt;            hint = self.rowhint[num]&lt;br /&gt;        workcopy = [self.board[i] for i in poss]&lt;br /&gt;        if not 0 in workcopy:&lt;br /&gt;            return False&lt;br /&gt;        memory = workcopy[:]&lt;br /&gt;        result = self.line_processor(hint, workcopy)&lt;br /&gt;        if memory == result:&lt;br /&gt;            return False&lt;br /&gt;        i = 0&lt;br /&gt;        for p, r, m in zip(poss, result, memory):&lt;br /&gt;            if r != m:&lt;br /&gt;                self.board[p] = r&lt;br /&gt;                if d == 'col':&lt;br /&gt;                    self.todo.add(('row', i))&lt;br /&gt;                    #print "ADD row", i&lt;br /&gt;                else: #'row'&lt;br /&gt;                    self.todo.add(('col', i))&lt;br /&gt;                    #print "ADD col", i&lt;br /&gt;            i += 1&lt;br /&gt;        return True&lt;br /&gt;&lt;br /&gt;    def try_solve(self):&lt;br /&gt;        while self.todo:&lt;br /&gt;            #print self.todo&lt;br /&gt;            p = self.todo.pop()&lt;br /&gt;            self.work_a_line(*p)&lt;br /&gt;&lt;br /&gt;    def dump(self):&lt;br /&gt;        for i in xrange(self.height):&lt;br /&gt;            t = self.board[i*self.width : (i+1)*self.width]&lt;br /&gt;            print t&lt;br /&gt;&lt;br /&gt;def my_logic(hint, ary):&lt;br /&gt;    #DETARAME!&lt;br /&gt;    if hint:&lt;br /&gt;        for i in xrange(hint[0]):&lt;br /&gt;            ary[i] = 1&lt;br /&gt;    return ary&lt;br /&gt;&lt;br /&gt;rowhint = [&lt;br /&gt;    [6],[2,1,2],[1,1,1,1],[1,1],[1,1],&lt;br /&gt;    [8],[2,2],[1,1],[1,1],[1,3,1],&lt;br /&gt;    [2,1,1,3],[2,3,3],[1,1,1],[1,1],[10],&lt;br /&gt;]&lt;br /&gt;colhint = [&lt;br /&gt;    [9],[6,2,1],[2,1,1],[1,1,1,4,1],[1,1,1,1,1],&lt;br /&gt;    [2,1,3,1],[1,1,1,1],[2,1,2,1,],[6,2,1],[9],&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;b = IllustLogic(my_logic, rowhint, colhint)&lt;br /&gt;b.try_solve()&lt;br /&gt;b.dump()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-6570837581683356933?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/6570837581683356933/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=6570837581683356933' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6570837581683356933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6570837581683356933'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python_29.html' title='pythonでお絵かきロジック(未完)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1033593694882172578</id><published>2008-06-26T23:22:00.004+09:00</published><updated>2008-06-26T23:39:34.986+09:00</updated><title type='text'>pythonサンプル・スクリプト中にビットマップ</title><content type='html'>pygameを使っている。&lt;br /&gt;普通は画像を外付けのファイルにして、それを必要なときにロードする。&lt;br /&gt;ここでは、スクリプトだけで画像ファイルの表示に相当することをやってみる。大して意味はないが、昔プログラムの投稿雑誌とかではグラフィックまで含めて一本のソースコードで表現していたことを思い出したりできる。カセットテープからCLOADするときにソースが複数だと面倒じゃん。（よく分からない人へ：冗談なので聞き流してよいです）&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sys&lt;br /&gt;import StringIO&lt;br /&gt;import base64&lt;br /&gt;import pygame&lt;br /&gt;import pygame.locals as C&lt;br /&gt;&lt;br /&gt;pygame.display.set_mode((320, 240))&lt;br /&gt;c = pygame.display.get_surface()&lt;br /&gt;&lt;br /&gt;bit = pygame.image.load(StringIO.StringIO(base64.decodestring(&lt;br /&gt; 'R0lGODdhCAAIAPoAMWQEBJwEBP///wAAAAAAAAAAAAAAAAAAACwAAAAACAAIAAADFyi6G+BhvRmneCJACiyujhIpnJAAAAAAADs=')))&lt;br /&gt;bit.set_colorkey(bit.get_at((0,0)))&lt;br /&gt;&lt;br /&gt;c.fill((255,255,255,255))&lt;br /&gt;c.blit(bit, (160, 120))&lt;br /&gt;pygame.display.flip()&lt;br /&gt;&lt;br /&gt;while True: &lt;br /&gt;  if pygame.event.poll().type == C.QUIT: sys.exit(0)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;途中の変な文字列がミソで、あらかじめ画像ファイルの中身ををbase64エンコードしたものをこうやって扱えばよい。ファイルのように扱える文字列として、StringIOオブジェクトをこしらえてからimage.loadに渡している。&lt;br /&gt;&lt;br /&gt;ところでこのbase64化した文字列をどうやって作るかというと、pythonの対話プロンプトから&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import base64&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print base64.encodestring(file('sample.gif', 'rb').read())&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;とでもして出したらよい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1033593694882172578?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1033593694882172578/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1033593694882172578' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1033593694882172578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1033593694882172578'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python_26.html' title='pythonサンプル・スクリプト中にビットマップ'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8898550735117901087</id><published>2008-06-23T21:51:00.001+09:00</published><updated>2008-06-23T21:55:42.801+09:00</updated><title type='text'>pythonサンプル・pygameでライフゲーム</title><content type='html'>先日書いたライフゲームをpygame版に書き直してみる。ゲーム製作用ライブラリなので、Tkinterよりスピーディで気持ちよい。&lt;br /&gt;pygameにまだ慣れないので、どうやってクラスにまとめるべきかはよく分からない。&lt;br /&gt;&lt;br /&gt;pygame: &lt;a href="http://www.pygame.org/news.html"&gt;http://www.pygame.org/news.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sys&lt;br /&gt;import pygame&lt;br /&gt;import pygame.locals as C&lt;br /&gt;from random import randint&lt;br /&gt;&lt;br /&gt;class LifeGame(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, xs=40, ys=40, fps=30):&lt;br /&gt;        self.xs = xs&lt;br /&gt;        self.ys = ys&lt;br /&gt;        self.fps = fps&lt;br /&gt;        self.b = [randint(0,1) for i in xrange(self.xs * self.ys)]&lt;br /&gt;        pygame.display.set_mode((self.xs*8, self.ys*8))&lt;br /&gt;        self.c = pygame.display.get_surface()&lt;br /&gt;&lt;br /&gt;    def run(self):&lt;br /&gt;        clock = pygame.time.Clock()&lt;br /&gt;        while True: &lt;br /&gt;            if pygame.event.poll().type == C.QUIT:&lt;br /&gt;                sys.exit(0)&lt;br /&gt;            self.progress()&lt;br /&gt;            clock.tick(self.fps)&lt;br /&gt;&lt;br /&gt;    def chst(self, p):&lt;br /&gt;        d = self.xs&lt;br /&gt;        n = 0&lt;br /&gt;        for i in (p-d-1, p-d, p-d+1, p-1, p+1, p+d-1, p+d, p+d+1):&lt;br /&gt;            try:&lt;br /&gt;                n += self.b[i]&lt;br /&gt;            except:&lt;br /&gt;                pass&lt;br /&gt;        if n &amp;lt; 2 or n &amp;gt; 3: return 0  #die&lt;br /&gt;        if n == 3: return 1          #born&lt;br /&gt;        return self.b[p]  #survive&lt;br /&gt;&lt;br /&gt;    def progress(self):&lt;br /&gt;        self.b = [self.chst(p) for p in xrange(len(self.b))]&lt;br /&gt;        self.c.fill(0x808080)&lt;br /&gt;        for i in xrange(self.xs):&lt;br /&gt;            for j in xrange(self.ys):&lt;br /&gt;                if self.b[self.xs*j+i]:&lt;br /&gt;                    f = 0&lt;br /&gt;                else:&lt;br /&gt;                    f = 0xffffff&lt;br /&gt;                pygame.draw.rect(self.c, f,&lt;br /&gt;                                 (i*8, j*8, 7, 7))&lt;br /&gt;        pygame.display.flip()&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    pygame.init()&lt;br /&gt;    LifeGame(60, 40, 20).run()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8898550735117901087?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8898550735117901087/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8898550735117901087' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8898550735117901087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8898550735117901087'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/pythonpygame.html' title='pythonサンプル・pygameでライフゲーム'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1172126935807788618</id><published>2008-06-21T12:01:00.002+09:00</published><updated>2008-06-21T12:07:25.189+09:00</updated><title type='text'>pythonで音声合成</title><content type='html'>AquesTalkという音声合成ライブラリを使って、簡単に音声合成を試してみることができる。&lt;br /&gt;&lt;a href="http://www.a-quest.com/aquestalk/"&gt;http://www.a-quest.com/aquestalk/&lt;/a&gt;からWin版(Free)の配布パッケージをダウンロードしてきて展開、その中のbinフォルダに必要なDLLがあるから、そこに AquesTalk.dll と AquesTalkDa.dll があることを確認して、同じディレクトリに下のようなスクリプトを作って実行してみるだけ。これで最低限の動作をする。(ctypesモジュールはpython2.5から標準配布されている)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- coding:cp932 -*-&lt;br /&gt;&lt;br /&gt;from ctypes import windll&lt;br /&gt;talk_dll = windll.LoadLibrary("AquesTalkDa.dll")&lt;br /&gt;v = talk_dll.AquesTalkDa_PlaySync&lt;br /&gt;v("うらにわに'わ/に'わ/にわに'わ/に'わ/にわとりが/いる。", 120)&lt;br /&gt;v("すもももももも/もものうち", 120)&lt;br /&gt;v("とうきょう/とっ'きょ/きょか'きょく/きょかきょく'ちょう", 120)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;下の記事を参考にさせていただきました。&lt;br /&gt;&lt;a href="http://boxheadroom.com/2008/04/18/aquestalk"&gt;http://boxheadroom.com/2008/04/18/aquestalk&lt;/a&gt;&lt;br /&gt;&lt;a href="http://d.hatena.ne.jp/tomoemon/20071116#p1"&gt;http://d.hatena.ne.jp/tomoemon/20071116#p1&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1172126935807788618?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1172126935807788618/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1172126935807788618' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1172126935807788618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1172126935807788618'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python_21.html' title='pythonで音声合成'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-4014742275359976840</id><published>2008-06-20T16:26:00.001+09:00</published><updated>2008-06-20T20:00:20.230+09:00</updated><title type='text'>pythonでライフゲーム</title><content type='html'>pythonの標準配布に含まれるTkinter（tkのラッパー）を使って何か表示してみるテスト。ここではライフゲームっぽいものを作ってみた。&lt;br /&gt;下のスクリプトを適当な名前(life.pyとか)で保存して実行すると、大きさの異なるふたつのライフゲームが異なる速度で進んでいく。ゲームといっても、眺めるだけ。&lt;br /&gt;&lt;br /&gt;スクリプトの途中に try: except: 構文で処理を書いているところだけを簡単に説明する。ライフゲームは自分のまわりの８個のコマに従って変化していくが、盤の端っこのコマにとっては部分的に存在しないマスを参照することになる。存在しないコマへのアクセスはpython的にはスクリプト終了級の事態なのだけど、exceptを使ってそのエラーを無視させてしまうことで、単に処理を飛ばすだけにとどめることができる。あまり正確な言い方ではないが。&lt;br /&gt;&lt;br /&gt;やる前に厳重にチェックしてエラーを防ぐより、やっちゃってみてからエラーが起きたら対処する、というやり方のほうが楽になることもある、という例。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import Tkinter&lt;br /&gt;from random import randint&lt;br /&gt;&lt;br /&gt;class LifeGame(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, xs=40, ys=40, interval=500):&lt;br /&gt;        self.xs = xs&lt;br /&gt;        self.ys = ys&lt;br /&gt;        self.interval = interval&lt;br /&gt;        self.b = [randint(0,1) for i in xrange(self.xs * self.ys)]&lt;br /&gt;        self.c = Tkinter.Canvas(width=self.xs*8, height=self.ys*8)&lt;br /&gt;        self.c.pack()&lt;br /&gt;        self.c.after(self.interval, self.progress)&lt;br /&gt;&lt;br /&gt;    def chst(self, p):&lt;br /&gt;        d = self.xs&lt;br /&gt;        n = 0&lt;br /&gt;        for i in (p-d-1, p-d, p-d+1, p-1, p+1, p+d-1, p+d, p+d+1):&lt;br /&gt;            try:&lt;br /&gt;                n += self.b[i]&lt;br /&gt;            except:&lt;br /&gt;                pass&lt;br /&gt;        if n &amp;lt; 2 or n &amp;gt; 3: return 0  #die&lt;br /&gt;        if n == 3: return 1          #born&lt;br /&gt;        return self.b[p]  #survive&lt;br /&gt;&lt;br /&gt;    def progress(self):&lt;br /&gt;        self.b = [self.chst(p) for p in xrange(len(self.b))]&lt;br /&gt;        for i in self.c.find_all(): self.c.delete(i)&lt;br /&gt;        for i in xrange(self.xs):&lt;br /&gt;            for j in xrange(self.ys):&lt;br /&gt;                if self.b[self.xs*j+i]:&lt;br /&gt;                    f = 'black'&lt;br /&gt;                else:&lt;br /&gt;                    f = 'white'&lt;br /&gt;                self.c.create_rectangle(i*8+2, j*8+2,&lt;br /&gt;                                        i*8+8, j*8+8, fill=f)&lt;br /&gt;        self.c.after(self.interval, self.progress)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    lg1 = LifeGame(50, 40)&lt;br /&gt;    lg2 = LifeGame(18, 18, 310)&lt;br /&gt;    Tkinter.mainloop()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-4014742275359976840?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/4014742275359976840/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=4014742275359976840' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4014742275359976840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4014742275359976840'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python_20.html' title='pythonでライフゲーム'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-2667654934240173592</id><published>2008-06-19T21:50:00.003+09:00</published><updated>2008-06-19T22:17:29.678+09:00</updated><title type='text'>pythonで難解バカボン</title><content type='html'>『難解バカボン』という、変な文章を作り出すソフトウェアがある。作者は難解計画氏。&lt;br /&gt;&lt;a href="http://www.vector.co.jp/soft/dos/amuse/se007728.html"&gt;http://www.vector.co.jp/soft/dos/amuse/se007728.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;オリジナルはC言語で書いてあるのを、pythonに移植してみた。下のソースを適当な名前(nankai.pyとか)で保存の上、オリジナルの難解バカボンに入っている辞書ファイル(*.nb1)を同ディレクトリにコピー等してから実行する。スクリプト中ではデフォルト値をnanba.nb1にしているが、これを変更することで、色々な辞書を使った変な文章が作れる。&lt;br /&gt;完全に移植してはいない。適当に翻案したり組み方を変えてしまったところもある。また、文章生成パラメータの説明も省略する。本物を参照のこと。&lt;br /&gt;&lt;br /&gt;スクリプトそのものについて説明できるところはない。前回のエントリで、面倒な辞書リテラル（ここでは入れ子リストのリテラル）を簡単に書く方法を書いたが、ここでこれの応用をしている。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- coding: cp932 -*-&lt;br /&gt;&lt;br /&gt;import random&lt;br /&gt;&lt;br /&gt;inf_raw = u'しない:せず はない:はなく がない:がなく にない:になく'\&lt;br /&gt; u'ている:ており でいる:でおり する:し ずる:じ ある:あり える:え'\&lt;br /&gt; u'げる:げ ぜる:ぜ める:め れる:れ 言う:言い いう:いい 入る:入り'\&lt;br /&gt; u'見る:見て 出る:出て 得る:得て しい:しく あう:あい 合う:合い'\&lt;br /&gt; u'だ:で く:き つ:ち む:み ぐ:ぎ ぶ:び'&lt;br /&gt;&lt;br /&gt;config_default = {'mn':1, 'mx':5, 'sn':6, 'rc':2, 'sc':60,&lt;br /&gt;          'sh':70, 'jt':50, 'sz':50, 'bm':50, 'kt':u'、', 'tt':u'。' }&lt;br /&gt;&lt;br /&gt;#WORDS_MAX = 2500&lt;br /&gt;#kugiri = u' !?:;.,^~_/&amp;lt;&amp;gt;()[]{}｢｣｡､･\'"\t\n　！？：；．，。、・\…'\&lt;br /&gt;#          u'‥＾￣＿／＜＞（）［］「」〔〕｛｝〈〉《》『』【】“”‘’'&lt;br /&gt;&lt;br /&gt;class NankaiBakabon(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, datafile='nanba.nb1'):&lt;br /&gt;        import copy&lt;br /&gt;        self.inf_dic = []&lt;br /&gt;        for i in inf_raw.split(" "): self.inf_dic.append(i.split(":"))&lt;br /&gt;        self.wlow = ([], [], [], [], [], [], [])&lt;br /&gt;        self.config = copy.copy(config_default)&lt;br /&gt;        self.read_data_config(datafile)&lt;br /&gt;&lt;br /&gt;    def set_config(self, key, val):&lt;br /&gt;        if key in ('mn', 'mx', 'sn', 'rc', 'sc', 'sh', 'jt', 'sz',&lt;br /&gt;                   'jt', 'sz', 'bm'):&lt;br /&gt;            self.config[key] = int(val)&lt;br /&gt;        elif key in ('kt', 'tt'):&lt;br /&gt;            self.config[key] = val.decode('cp932')&lt;br /&gt;&lt;br /&gt;    def read_data_config(self, datafile):&lt;br /&gt;        f = open(datafile, 'r')&lt;br /&gt;        wtype = 0&lt;br /&gt;        wcount = 0&lt;br /&gt;        for line in f:&lt;br /&gt;            line = line[:-1]&lt;br /&gt;            a = line.find("'")&lt;br /&gt;            if a != -1: line = line[:a]&lt;br /&gt;            if not line: continue&lt;br /&gt;            if line.startswith('-'):&lt;br /&gt;                key = line[1:3].lower()&lt;br /&gt;                val = line[3:].strip(' \t\"\'')&lt;br /&gt;                self.set_config(key, val)&lt;br /&gt;                continue&lt;br /&gt;            if line.startswith('@'):&lt;br /&gt;                wtype += 1&lt;br /&gt;                continue&lt;br /&gt;            self.wlow[wtype].append(line.decode('cp932'))&lt;br /&gt;            wcount += 1&lt;br /&gt;        f.close()&lt;br /&gt;        print wcount, u"個の語句を読み込みました"&lt;br /&gt;&lt;br /&gt;    def test_dice(self, attr):&lt;br /&gt;        return random.randint(0, 100) &amp;lt; self.config[attr]&lt;br /&gt;&lt;br /&gt;    def sel(self, wtype, buf):&lt;br /&gt;        sz_limit = 15&lt;br /&gt;        fm_limit = 15&lt;br /&gt;        while 1:&lt;br /&gt;            b = random.choice(self.wlow[wtype])&lt;br /&gt;            if len(buf) == 0: break&lt;br /&gt;            #形容詞のあとの書き出しを制限（副作用大きい）&lt;br /&gt;            #if buf[-1].endswith(u'い'):&lt;br /&gt;            #     形容詞のあとの単語を制限&lt;br /&gt;            #    if b[:2] in (u'べき', u'べか', u'べく', u'べし', u'しか',&lt;br /&gt;            #                 u'ため', u'には', u'まで'):&lt;br /&gt;            #        print "[WARNING]" + buf[-1] + b&lt;br /&gt;            #        continue&lt;br /&gt;&lt;br /&gt;            #接続助詞の重複感を(できるだけ)避ける&lt;br /&gt;            if sz_limit &amp;gt; 0:&lt;br /&gt;                if buf[-1][-2:].rstrip(self.config['tt']) == \&lt;br /&gt;                         b[-2:].rstrip(self.config['tt']):&lt;br /&gt;                    #print "[WARNING]" + buf[-1] + b, sz_limit&lt;br /&gt;                    sz_limit -= 1&lt;br /&gt;                    continue&lt;br /&gt;&lt;br /&gt;            #述語語尾の重複感を(できるだけ)避ける(TODO)&lt;br /&gt;&lt;br /&gt;            #語句の重複感を(できるだけ)避ける&lt;br /&gt;            f = 0&lt;br /&gt;            if fm_limit &amp;gt; 0:&lt;br /&gt;                for i in (u'であ', u'され', u'とい', u'と言',&lt;br /&gt;                          u'でき', u'もの'):&lt;br /&gt;                    if buf[-1].find(i) &amp;gt; -1 and b.find(i) &amp;gt; -1:&lt;br /&gt;                        #print "[WARNING]" + buf[-1] + b, fm_limit&lt;br /&gt;                        fm_limit -= 1&lt;br /&gt;                        f = 1&lt;br /&gt;            if f == 1: continue&lt;br /&gt;            &lt;br /&gt;            break&lt;br /&gt;        buf.append(b)&lt;br /&gt;&lt;br /&gt;    def inflect(self, buf):&lt;br /&gt;        for i in self.inf_dic:&lt;br /&gt;            if buf.endswith(i[0]):&lt;br /&gt;                buf = buf[:-len(i[0])] + i[1] + self.config['tt']&lt;br /&gt;                return buf&lt;br /&gt;        return buf + u'し' + self.config['tt']&lt;br /&gt;&lt;br /&gt;    def make_sentence(self):&lt;br /&gt;        buf = []&lt;br /&gt;        slen = random.randint(self.config['mn'], self.config['mx'])&lt;br /&gt;        a = 0&lt;br /&gt;        while True:&lt;br /&gt;            st = 1&lt;br /&gt;            #主語前の副詞&lt;br /&gt;            if self.test_dice('sh'):&lt;br /&gt;                self.sel(2, buf)&lt;br /&gt;                st = 0&lt;br /&gt;            #主語・助詞&lt;br /&gt;            if st == 1 or self.test_dice('sc'):&lt;br /&gt;                self.sel(0, buf)&lt;br /&gt;                self.sel(1, buf)&lt;br /&gt;            #主語後の副詞&lt;br /&gt;            if self.test_dice('sh'):&lt;br /&gt;                self.sel(2, buf)&lt;br /&gt;            #述語&lt;br /&gt;            if self.test_dice('jt'):&lt;br /&gt;                #他動詞&lt;br /&gt;                self.sel(0, buf)&lt;br /&gt;                self.sel(4, buf)&lt;br /&gt;            else:&lt;br /&gt;                #自動詞&lt;br /&gt;                self.sel(3, buf)&lt;br /&gt;            a += 1&lt;br /&gt;            if a &amp;gt;= slen: break&lt;br /&gt;            if self.test_dice('sz'):&lt;br /&gt;                #接続句から並列文へ&lt;br /&gt;                self.sel(5, buf)&lt;br /&gt;            else:&lt;br /&gt;                #語形変化で接続して並列文へ&lt;br /&gt;                buf[-1] = self.inflect(buf[-1])&lt;br /&gt;        #文末&lt;br /&gt;        if self.test_dice('bm'):&lt;br /&gt;            self.sel(6, buf)&lt;br /&gt;        buf.append(self.config['kt'])&lt;br /&gt;        #return buf&lt;br /&gt;        return "".join(buf)&lt;br /&gt;&lt;br /&gt;    def run(self):&lt;br /&gt;        while 1:&lt;br /&gt;            for i in xrange(self.config['sn']):&lt;br /&gt;                print self.make_sentence(),&lt;br /&gt;            print; print&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    NankaiBakabon('nanba.nb1').run()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;以下、実行結果の例。&lt;br /&gt;&lt;br /&gt;つくづく結構死体になるしかないかもしれませんがそれにしてもコカインはすっかり墓石を売り飛ばすとは恐怖でしょう。 とりあえずつくづく油揚を破壊する今日この頃ですがまず墓石を利用するので感心するよーに。 ティッシュも特に陰謀を穴に埋めるとはゆーもののテクノロジーはついに埋葬されると思いますです。 主として閑古鳥だってほとんどマネキンをやめる。&lt;br /&gt;&lt;br /&gt;ティッシュはまず芸者を手に入れるに決まってます。 彼岸は結構コカインを見るとか言いつつもキムチがどーにもこーにも死体を繰り広げるみたいっすね。 お姉さまは救いよーがないなんて知らんのでますますすかさずのたうつなんて知らんのですかさず暴れるざます。 ひねもすオリジナリティの野郎が死体を破壊するんだから結構つまり蝋燭を練り練りするので感心するよーに。&lt;br /&gt;&lt;br /&gt;油揚が閑古鳥を推進し、なるべくウィルスはいつでもとぐろを巻くみたいっすね。 五寸釘だって石燈篭とは違うらしいですがしかもスキャンダルをやめると思いますです。 ほとんどチェーンソーとゆーのは貝柱を利用し、もれなくナスビを開発するのでワケわからないす。 アンドロメダ病原体のくせにやっぱしヒロポンを開発するでしょう。&lt;br /&gt;&lt;br /&gt;臓物がまずわななくので怪しげですがもれなく一応蝋燭とは違うので焦ります。 彼岸は貝柱を利用する場合一応アンドロメダ病原体の野郎がそれにしてもヘチマを売り飛ばすなんて知りません。 つくづくキノコに関心を寄せるし、マネキンだけが狂うし、とりあえずつまり暴れるので危険です。 ひねもす朝日新聞のくせにわななき、思わずバリウムもめでたいし、結局パンチパーマの野郎がコカインを貰うんでしょーか。&lt;br /&gt;&lt;br /&gt;やっぱし卒塔婆がどーにもこーにもキノコにはならない今日この頃ですが一気に能面は実にモアイを用意するとゆー噂ですがわりと土管がどーにもこーにも死ぬとゆーことでしょう多分。 芸者はまさしく土管とは違うと思いますです。 土管だけが盛大にわななくのでワケわからないす。 たまにモアイがすでにカフェインを穴に埋めるとゆーことでしょう多分。&lt;br /&gt;&lt;br /&gt;そのうち盛大に幼女を開発するよーですがマンホールのくせにそのうちヘロインにはかなわないなんて信じられません。 なるべく包丁が結局死体になるしかないし、霊園の野郎が包丁を切り刻むとゆーのは実に往生際は頭金を切り刻むのだーだーだー。 謹んで馬はいつでも脳みそ腐るし、霊界ではもれなく彼岸にはかなわないなんて知りません。 どーにもこーにも朝日新聞を貰うし、それにしても蝋燭はもれなく救いよーがなく、キムチが思わず埋めてしまいたいんでしょーか。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-2667654934240173592?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/2667654934240173592/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=2667654934240173592' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2667654934240173592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2667654934240173592'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python.html' title='pythonで難解バカボン'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8852772214732166878</id><published>2008-06-18T21:08:00.002+09:00</published><updated>2008-06-18T21:14:01.516+09:00</updated><title type='text'>pythonサンプルコード(5)</title><content type='html'>辞書（連想配列とかハッシュと呼ばれるときもある）はもちろんpythonにも実装されていて、非常に有用です。でもリテラル表現で辞書をセットするのは書き方がやや煩雑です。特に日本語が混じったりして、ユニコード表現(u)が混じってくると、下のような打ち込むのが大変なコードになります。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;inf_dic = { u'しない':u'せず', u'はない':u'はなく', u'がない':u'がなく',&lt;br /&gt;            u'にない':u'になく', u'ている':u'ており', u'でいる':u'でおり',&lt;br /&gt;            u'する':u'し', u'ずる':u'じ', u'ある':u'あり', u'える':u'え',&lt;br /&gt;            u'げる':u'げ', u'ぜる':u'ぜ', u'める':u'め', u'れる':u'れ',&lt;br /&gt;            u'言う':u'言い', u'いう':u'いい', u'入る':u'入り',&lt;br /&gt;            u'見る':u'見て', u'出る':u'出て', u'得る':u'得て', u'しい':u'しく',&lt;br /&gt;            u'あう':u'あい', u'合う':u'合い', u'だ':u'で', u'く':u'き',&lt;br /&gt;            u'つ':u'ち', u'む':u'み', u'ぐ':u'ぎ', u'ぶ':u'び'}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;こんなのを書くよりは、最初にこれを作るための決まりをもった文字列を準備して、これを必要に応じて文字列操作で辞書に作り上げてしまったほうが、作成はかえって楽です。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;inf_raw = u'しない:せず はない:はなく がない:がなく にない:になく'\&lt;br /&gt; u' ている:ており でいる:でおり する:し ずる:じ ある:あり える:え'\&lt;br /&gt; u' げる:げ ぜる:ぜ める:め れる:れ 言う:言い いう:いい 入る:入り'\&lt;br /&gt; u' 見る:見て 出る:出て 得る:得て しい:しく あう:あい 合う:合い'\&lt;br /&gt; u' だ:で く:き つ:ち む:み ぐ:ぎ ぶ:び'&lt;br /&gt;&lt;br /&gt;inf_dic = {}&lt;br /&gt;for i in inf_raw.split(" "):&lt;br /&gt;    (k, v) = i.split(":")&lt;br /&gt;    inf_dic[k] = v&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;どっちも同じinf_dic辞書ができ上がります。こんな感じで確かめました。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print inf_dic[u'言う']&lt;br /&gt;言い&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8852772214732166878?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8852772214732166878/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8852772214732166878' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8852772214732166878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8852772214732166878'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python5.html' title='pythonサンプルコード(5)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-2386108097457472987</id><published>2008-06-17T20:43:00.004+09:00</published><updated>2008-06-17T20:53:12.747+09:00</updated><title type='text'>pythonサンプルコード(4)</title><content type='html'>いつかperlで書いたことのある、デタラメ書名を作り出すスクリプトをpythonに移植した。使い道は、謎。&lt;br /&gt;ソースコードはutf-8で保存すること。一行目に encoding: utf-8 と書いたから。ここでシフトJIS(cp932)と書くときは、シフトJISで保存すればよいのだけど。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# -*- encoding: utf-8 -*-&lt;br /&gt;#でたらめな書名を作る。&lt;br /&gt;import random&lt;br /&gt;&lt;br /&gt;a = u"着衣 人間 デンマーク 霧氷 砂漠 雨 鉄道 正義 心臓 血流 詩人 環境"\&lt;br /&gt;    u" 権利 熱帯 ナマコ 人種 マーケティング 幕末 光合成 修道院 歴史"\&lt;br /&gt;    u" 芸術 回想 芸能".split(" ")&lt;br /&gt;b = u"早分かり・%s 小説・%s 判例で学ぶ%s 本当はおそろしい%s いちばん詳しい%s %sの研究"\&lt;br /&gt;    u" %sを歩く %s事典 %s大百科 %sだいすき %s入門 %s超入門 %sってなんだろう %sの心理学"\&lt;br /&gt;    u" %sハンドブック・改訂版 %sがわかる %s大好き！ %sを求めて %s年鑑 %sの謎を追う"\&lt;br /&gt;    u" %sの歴史 %sの裏側 %s物語 次代に伝える%s ヒゲの先生、%sを語る".split(" ")&lt;br /&gt;c = u"の の と 的な".split(" ")&lt;br /&gt;c.append("")&lt;br /&gt;d = u"%s学 %s論 %s派 %s主義 反%s %s %s %s %s".split(" ")&lt;br /&gt;&lt;br /&gt;def getMeisi():&lt;br /&gt;    return random.choice(d) % random.choice(a)&lt;br /&gt;&lt;br /&gt;def getMeisiKu(p):&lt;br /&gt;    r = p - random.random()&lt;br /&gt;    if r &amp;gt; 0.0:&lt;br /&gt;        return getMeisi()&lt;br /&gt;    else:&lt;br /&gt;        return getMeisi() + random.choice(c) + getMeisiKu(r)&lt;br /&gt;&lt;br /&gt;def getDetarameBookTitle():&lt;br /&gt;    title = getMeisiKu(0.7)&lt;br /&gt;    if random.random() &amp;gt; 0.2:&lt;br /&gt;        title = random.choice(b) % title&lt;br /&gt;    return title&lt;br /&gt;&lt;br /&gt;for i in xrange(0,10): print getDetarameBookTitle()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;今回このスクリプトをことごと説明はしない。ただ、randomモジュールの使いかたにだけ触れておく。&lt;br /&gt;random.random() ... 0.0以上1.0未満の乱数を発生する。&lt;br /&gt;random.choice(a) ... 配列aから適当にいっこ取り出す。&lt;br /&gt;random.randint(a, b) ... aからbまでの整数をランダムに発生する。今回は使ってないけど。&lt;br /&gt;&lt;br /&gt;実行結果はこんなふう…&lt;br /&gt;&lt;br /&gt;反環境事典&lt;br /&gt;ナマコ&lt;br /&gt;砂漠派の修道院&lt;br /&gt;早分かり・心臓的な回想主義の人間学&lt;br /&gt;ナマコ論と環境の血流学&lt;br /&gt;霧氷論の血流&lt;br /&gt;芸術&lt;br /&gt;マーケティング派&lt;br /&gt;熱帯的な砂漠派&lt;br /&gt;回想と心臓&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-2386108097457472987?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/2386108097457472987/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=2386108097457472987' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2386108097457472987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2386108097457472987'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python4.html' title='pythonサンプルコード(4)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-6412482063022089873</id><published>2008-06-17T15:06:00.003+09:00</published><updated>2008-06-17T15:15:55.416+09:00</updated><title type='text'>pythonサンプルコード(3)</title><content type='html'>おもちゃだけど、下の二行を書いたスクリプトを実行してみると、&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import SimpleHTTPServer&lt;br /&gt;SimpleHTTPServer.test()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Serving HTTP on 0.0.0.0 port 8000 ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;なんていう表示がされて、一見動作が止まる。（Windowsだと、なんか警告みたいなのが出るときがある。一時的に云々…というボタンを押して、やり過ごしておく）&lt;br /&gt;&lt;br /&gt;で、手持ちのWebブラウザで、アドレス欄に http://127.0.0.1:8000/ と入力してみると、なんと簡単なWebサーバーができてしまったことがわかる。&lt;br /&gt;&lt;br /&gt;これだけだと大した役にはたたないけど、これを骨組みに改良していくことで、実用的なアプリケーションに育てていくこともできる。&lt;br /&gt;また、SimpleHTTPServerのモジュールソースを読むのは楽しくて勉強になる。&lt;br /&gt;&lt;br /&gt;サンプルの動作を止めるには、Ctrl+Cを押しても、コマンドプロンプトの窓を直接閉じてもよい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-6412482063022089873?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/6412482063022089873/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=6412482063022089873' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6412482063022089873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/6412482063022089873'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python3.html' title='pythonサンプルコード(3)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-2636357535914252315</id><published>2008-06-17T09:53:00.003+09:00</published><updated>2008-06-17T14:54:25.284+09:00</updated><title type='text'>pythonサンプルコード(2)</title><content type='html'>書いたコードをHTMLに載せるのに、コードをそのまま切って貼ると都合が悪いときがある。&lt;br /&gt;&lt;br /&gt;ひとつはタブ記号によるインデントが再現できないこと、もうひとつは松葉括弧がタグとみなされて表示が壊れてしまうことである。&lt;br /&gt;&lt;br /&gt;ブログ用のソフトウェアによってはちゃんと対応してくれるが、bloggerに直接書こうとするとやっぱりこのための手間をかける必要があった。&lt;br /&gt;&lt;br /&gt;ということで、手持ちのスクリプトを貼り付け用HTMLに直す処理自体をスクリプトに書いた。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;w = 72&lt;br /&gt;&lt;br /&gt;for line in sys.stdin:&lt;br /&gt;    line = line[:-1]&lt;br /&gt;    if not line:&lt;br /&gt;        print&lt;br /&gt;        continue&lt;br /&gt;    line = line.expandtabs(4)&lt;br /&gt;    while line:&lt;br /&gt;        (a, line) = line[:w], line[w:]&lt;br /&gt;        print a.replace('&amp;amp;', '&amp;amp;amp;').replace('&amp;lt;', '&amp;amp;lt;')\&lt;br /&gt;               .replace('&amp;gt;', '&amp;amp;gt;')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;import sysしてからforループでsys.stdin（標準入力）を処理するという書き方はお決まりのもので、もう考えなくても手が動く。ついでに、次のline[:-1]という書き方は、行末の改行記号を取り除くという、これもお決まりの書き方。&lt;br /&gt;&lt;br /&gt;expandtabsメソッドは、文字列に含まれるタブ記号を空白文字の集まりに置き換えるもの。(4)だからタブひとつあたり空白4文字になる。&lt;br /&gt;次の while line ループは、lineが空っぽになるまで続けるよという書き方。ループの中でlineはだんだん短くなっていく。具体的には、左72文字分を切りながらaに渡し続けることによって。&lt;br /&gt;aを出力するときは、HTMLでよくある &amp;amp;、 &amp;gt;、 &amp;lt; を対応するHTML上の書き方に変換してから表示している。replaceメソッドの戻り値もまた文字列だから、サンプルに書いたようなつなげ方で書ける。&lt;br /&gt;円記号（環境によっては逆スラッシュ記号）は、次の行に続くよという目印。一行が長すぎると思ったら適宜改行することにする。&lt;br /&gt;&lt;br /&gt;このスクリプトがpy2html.pyという名前だとしたら、これの使い方は&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;cat py2html.py | python py2html.py&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;って感じ。この例では自分自身を整形してみせる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-2636357535914252315?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/2636357535914252315/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=2636357535914252315' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2636357535914252315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/2636357535914252315'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python2.html' title='pythonサンプルコード(2)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1068478356577031313</id><published>2008-06-17T08:38:00.008+09:00</published><updated>2008-06-19T09:57:05.489+09:00</updated><title type='text'>pythonサンプルコード(1)</title><content type='html'>pythonのサンプルでも書いて暮らしてみようと思った。&lt;br /&gt;とりあえず、W3CのトップページのHTMLを持ってくるようなサンプル。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import urllib2&lt;br /&gt;url = 'http://www.w3c.org/'&lt;br /&gt;print urllib2.urlopen(url).read()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;こいつにsample.pyとでも何とでも名づけて保存し、コマンドプロンプトから実行。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;python sample.py&lt;br /&gt;（実行結果）&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.&lt;br /&gt;org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US"&lt;br /&gt;&amp;gt;&lt;br /&gt;&amp;lt;head profile="http://www.w3.org/2000/08/w3c-synd/#"&amp;gt;&amp;lt;meta http-equiv="C&lt;br /&gt;ontent-Type" content="text/html; charset=utf-8" /&amp;gt;&lt;br /&gt;&amp;lt;meta name="generator" content="HTML Tidy for Mac OS X (vers 1st March 2&lt;br /&gt;004), see www.w3.org" /&amp;gt;&lt;br /&gt;&amp;lt;meta name="keywords" content="W3C, World Wide Web, Web, WWW, Consortium&lt;br /&gt;, computer, access, accessibility, semantic, worldwide, W3, HTML, XML, s&lt;br /&gt;tandard, language, technology, link, CSS, RDF, XSL, Berners-Lee, Berners&lt;br /&gt;, Lee, style sheet, cascading, schema, XHTML, mobile, SVG, PNG, PICS, DO&lt;br /&gt;M, SMIL, MathML, markup, Amaya, Jigsaw, free, open source, software" /&amp;gt;&lt;br /&gt;&amp;lt;meta name="description" content="The World Wide Web Consortium (W3C) is&lt;br /&gt;...ごちゃごちゃ&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;標準出力に出てくるだけでは嫌なら、ファイルを書き込み用に開いてそこにwriteすればいい。'wb'のうちwが「書き込み用OPEN」っていう意味で、bが「バイナリモード」って意味。bは今のところこれ以上の説明を割愛。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import urllib2&lt;br /&gt;url = 'http://www.w3c.org/'&lt;br /&gt;f = open('index.html', 'wb')&lt;br /&gt;f.write(urllib2.urlopen(url).read())&lt;br /&gt;f.close()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ところで、read() をたまに read とだけ書いてしまうことがありますが、これだと動かないです。括弧をつけないと、メソッドそのものを返すという動作になり、意図と違うことになります。python練習中にはよくやるミスです。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; 'hello'.upper  # 大文字で表示するメソッド呼んでるつもり…&lt;br /&gt;&amp;lt;built-in method upper of str object at 0x00CD51A0&amp;gt;  # なんか出た！&lt;br /&gt;  #これはメソッドの内部形式みたいなもの。こんなのが欲しいんじゃない&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; 'hello'.upper()  # 括弧をつけて、メソッドを呼んでいることを明記&lt;br /&gt;'HELLO'  # これでいい&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1068478356577031313?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1068478356577031313/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1068478356577031313' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1068478356577031313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1068478356577031313'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/06/python1.html' title='pythonサンプルコード(1)'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5960337899255347876</id><published>2008-04-23T01:01:00.002+09:00</published><updated>2008-04-23T01:31:51.885+09:00</updated><title type='text'>時間を寸断される</title><content type='html'>スクリプトなんかを書いているときに他用でちょっとでも中断が入ると、再開してもいきなり能率が落ちたりする。&lt;br /&gt;僕のような凡人では、簡単なスクリプトなんかを書くだけでも多くの集中力を必要とするのだなと分かる。ちょっとしたミスで大事なデータを壊してしまったら大変だから。&lt;br /&gt;僕の個人的なイメージだが、スクリプトの挙動を頭の中で想像しながら書くには、意識の中にそれなりの空間を作って、そこで思考実験みたいなことを繰り返す必要がある。ほかごとに気が散ってしまうとこの「空間」が壊れてしまうので、またこれをがんばって作り直してから作成の続きをするはめになる。この作り直しの時間がロスになるわけ。&lt;br /&gt;&lt;br /&gt;だから何時間も邪魔しないでくれ、と言ってみたくもなるが、仕事でやる以上それも無理だったりするから、書こうとしていることをさらに細かい要素に分けて、ひとつづつの目標地点を単純なものにしていく。で、ひとつあたりの必要な連続時間を短くする。&lt;br /&gt;&lt;br /&gt;ひとつのスクリプトを複数の細かい要素に分けることそれ自体もそれなりの技能を必要とすることではあるけど、楽するためのスキルだと思えばがんばって上達させようと思える。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5960337899255347876?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5960337899255347876/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5960337899255347876' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5960337899255347876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5960337899255347876'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/04/blog-post_23.html' title='時間を寸断される'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3275043973998376167</id><published>2008-04-16T19:07:00.005+09:00</published><updated>2008-04-23T01:01:37.738+09:00</updated><title type='text'>紛失リスク、漏洩リスク</title><content type='html'>データを管理することについてぼんやり考えているうちに、悩みのすべては根本的にはデータ紛失のリスクとデータ漏洩のリスクのどちらかだなと思いついた。当然すぎることではあるけど、今さら。&lt;br /&gt;&lt;br /&gt;データ紛失のリスクとは、文字通りデータがなくなるリスク。旧バージョンのものを上書きしてしまったりすることも含む。また、どの情報が最新なのかが分からなくなってしまうようなときも、結果として紛失みたいなものだと思う。&lt;br /&gt;漏洩のほうは、意図しない相手にデータを与えてしまうリスク。P2Pとかで巷で大流行のやつ。パスワード管理なんてのは、データ漏洩リスクを管理することそのものだ。&lt;br /&gt;&lt;br /&gt;データを管理しとけ、って言われたら、とりあえず紛失も漏洩もするなよ、ということと捉えれば大きく間違ってはいないだろう。&lt;br /&gt;&lt;br /&gt;さて、ある部署で、データの管理のためと称して、ネットワークストレージ(NAS)を導入したとする。このことだけを取ったときに、これは上の二つのどっちのリスクを軽減するか。&lt;br /&gt;紛失のリスクは？別に減ってはいない。たとえNASがディスクの冗長化などで壊れにくくなっているとしても、人間がやるデータの上書きや消去なんかは簡単だ。それにファイルが長年無秩序にたまり続けてロクに検索ができなくなってしまったら、そんなの紛失してるのと同じだ。それに何より、皆が根拠のない安心感を持って蓄積し続けたデータが、ある日NASの故障で一網打尽に失われる、という恐ろしいことも、運用次第ではありうる。&lt;br /&gt;漏洩のリスクは？増えるとも減るともいえないが、増える可能性のほうが大きいんじゃないだろうか。多分部署の構成員だけに読めるようにパスワードでもかけて管理しておくだろうが、構成員が異動したときに、ついパスワードの組み換えをサボってしまう、とかそんなこともあるかも知れない。&lt;br /&gt;&lt;br /&gt;今後も、このソリューションはデータの紛失と漏洩のどっちを減らすつもりなのか、と考えてみるようにしたい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3275043973998376167?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3275043973998376167/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3275043973998376167' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3275043973998376167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3275043973998376167'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/04/blog-post_16.html' title='紛失リスク、漏洩リスク'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3744580487838602426</id><published>2008-04-10T22:28:00.003+09:00</published><updated>2008-04-10T23:41:10.000+09:00</updated><title type='text'>ブラックボックス化</title><content type='html'>仕事がブラックボックス化すると、とてもよくない。&lt;br /&gt;&lt;br /&gt;特に、コンピュータ上で何かの仕組みを作りこんだときによく起こる。&lt;br /&gt;典型的には、「このボタンを押すとこういう表示が出るから、ここでこのボタンを押してね。理由は僕も分からないけど、こうしないと次の処理がおかしくなるから」といった場面で仕事のブラックボックス化が起こり、これが固定される。&lt;br /&gt;&lt;br /&gt;結局何を実現するための手続きなのか、内部的には何が起こるのか、といったことをあわせて伝えておかないと、または自分自身でも理解しておかないと、工夫の余地が失われてしまって、伝えられた手続きからちょっとでも外れたことが恐ろしくてできなくなってしまう。&lt;br /&gt;&lt;br /&gt;ここでシステムの「疎外」がおこり、人間の支配を離れたシステムが逆に人間を支配し始める…とか大げさなことを言うつもりはないが、なんせ人に仕事を渡す／人から仕事を渡されるときはもっとスムーズにやれる方法はあるだろうにと痛感するんだよな。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3744580487838602426?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3744580487838602426/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3744580487838602426' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3744580487838602426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3744580487838602426'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/04/blog-post_10.html' title='ブラックボックス化'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7019183855851336571</id><published>2008-04-09T21:45:00.004+09:00</published><updated>2008-04-09T22:33:28.845+09:00</updated><title type='text'>Google App Engine</title><content type='html'>手元のwinXPで試してみることにする。&lt;br /&gt;&lt;br /&gt;まずpythonを2.5.2にアップグレードして、次に、GoogleAppEngineのインストーラを実行。インストール先のパスが、path環境変数に追加された。でもpythonへのパスは通ってないので、c:\python25もさらに追加。&lt;br /&gt;&lt;br /&gt;で、適当なところにディレクトリを掘って、そこにちょっとしたpythoコードとアプリケーションを定義するYAMLを書く。ここらへんは Getting Started とかいう記事を見ながらほぼそのままに。&lt;br /&gt;&lt;br /&gt;で、コマンドを一発叩いて簡易Webサーバーが上がって、ブラウザでアクセスするとすぐに動作を確認できる。&lt;br /&gt;&lt;br /&gt;ベースはDjangoかー。で、Googleがこれを拡張して、ユーザー認証とかデータベースとかをむちゃくちゃ簡単に扱えるようにしている。Djangoだから、この前ちょっと勉強したテンプレートの知識もそのまま使えると。自分もDjangoに目をつけてたのが、ちょっと嬉しい。&lt;br /&gt;&lt;br /&gt;予備知識のおかげで、サンプルコードはすぐに理解できる。とても楽しいオモチャだ。なんか書いて、Googleにホスティングしてみたいな。ということで登録待ちの予約を入れてしまった。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7019183855851336571?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7019183855851336571/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7019183855851336571' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7019183855851336571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7019183855851336571'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/04/google-app-engine.html' title='Google App Engine'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5013319199069218734</id><published>2008-04-08T23:35:00.002+09:00</published><updated>2008-04-08T23:51:26.180+09:00</updated><title type='text'>root権限を畏れよ</title><content type='html'>こんなことを言わなくても、誰でもrootを畏れるようになるけどね。ただし失敗したあとで。願うらくはその失敗が社会をマヒさせるような種類のものでありませんように。&lt;br /&gt;&lt;br /&gt;UNIX系のスーパーユーザーになってするべき作業は多い。コマンドのインストールとか、ユーザー作成とか。スーパーユーザーはどんなファイルでも削除や改変ができて、どんなプロセスも殺せます。&lt;br /&gt;&lt;br /&gt;ノッて作業していると、思わぬところで変な間違いをしてしまう。大事な設定ファイルをバックアップ取らずに編集しちゃったとか、消しちゃったとか。あとは作業ディレクトリを消そうとして本環境を丸っと消しちゃうとか。&lt;br /&gt;&lt;br /&gt;筆者だけかも知れませんが、catとrmをうっかり打ち間違うことがあるのです。なぜかは分からない。ファイルを眺めるだけのつもりが、サッパリ消してしまう。これはショック大きいです。&lt;br /&gt;&lt;br /&gt;UNIX系ってサーバーとして動いているときが多いので、最悪、皆の仕事を止めてしまうような失敗もありうる。怖いです。&lt;br /&gt;&lt;br /&gt;基本的に、必要なとき以外はスーパーユーザーにならないのがよいです。で、必要な仕事が終わったらとっととスーパーユーザーを抜ける。&lt;br /&gt;&lt;br /&gt;スーパーユーザーの状態でファイルを消したり、ディレクトリを消したりするのは最大限の注意を払うこと。削除のかわりにファイル名やディレクトリ名を変える程度にしておいて、後日全く問題ないことを確認してから本当に削除するとか、そういう工夫もアリ。自分がちょっとでも興奮状態などで判断が鈍っているという自覚がある場合は、スーパーユーザーにならないこと。可能なら、二人以上で確認しあいながら作業すること。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5013319199069218734?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5013319199069218734/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5013319199069218734' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5013319199069218734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5013319199069218734'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/04/root.html' title='root権限を畏れよ'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-3681410081227983519</id><published>2008-04-08T00:08:00.001+09:00</published><updated>2008-04-08T00:19:18.119+09:00</updated><title type='text'>ブランクがあいている</title><content type='html'>忘れているわけでもないが、ここの更新が滞った。&lt;br /&gt;備忘的な意味を込めて、とりあえずエントリだけ作る。&lt;br /&gt;&lt;br /&gt;次は「スーパーユーザー権限を畏れよ」の巻。の予定&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-3681410081227983519?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/3681410081227983519/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=3681410081227983519' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3681410081227983519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/3681410081227983519'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/04/blog-post.html' title='ブランクがあいている'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-692540258273255772</id><published>2008-01-21T23:10:00.000+09:00</published><updated>2008-01-26T23:06:45.925+09:00</updated><title type='text'>階層型メモ</title><content type='html'>メモの管理が劇的に変わったのは、階層型メモを使うようになってから。&lt;br /&gt;&lt;br /&gt;それまでは、&lt;br /&gt;・notepadとかで単に書き残す&lt;br /&gt;・付箋ソフトみたいなやつに書き残す&lt;br /&gt;・メールとして自分に送り、マークとかフォルダ分けとかしてみる&lt;br /&gt;などと色々試したが、なんだかうまくいかなかった。&lt;br /&gt;&lt;br /&gt;一番やりたかったことは、自分の目前にある仕事を整理するとともに、やっていること・やってきたことのカテゴリー化を体系的に行うことだった。これはうまくツリー型のメモとしておさまり、それまでは「なんだか何でもかんでもやらされてる気がして、忙しさが終わる気がしなくて腹が立つ」という状態だったのが、気分的にたいへん楽になった。&lt;br /&gt;&lt;br /&gt;仕事上のメモはとりあえず新しい項目として突っ込んでおき、あとでそれを適当なツリー上に置きなおして、付近にある仕事との関係をそのつど確認しておく。そうすると、類似の仕事をまとめて単純な形に直してしまうことを思いつくかも知れないし、または、片手間のつもりの仕事と思っていたものについて、それが積もってきて、新しいカテゴリーを作ってちゃんと労力を集中したほうがよいと気づくかも知れない。&lt;br /&gt;&lt;br /&gt;ドキュメントは大きなツリーをもつものを主にひとつだけ管理することにして、マスターメモと名づけた。これが失われるととても困るので、バックアップを神経質に取るようになった。&lt;br /&gt;&lt;br /&gt;FitzNOTEを結構長く使ったあと、Nami2000に乗り換えた。後者のほうがデータファイルの構成が単純で、単にテキストファイルとして開いてもほとんど問題なく読めるから。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-692540258273255772?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/692540258273255772/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=692540258273255772' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/692540258273255772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/692540258273255772'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/01/blog-post_21.html' title='階層型メモ'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1385703033914536586</id><published>2008-01-18T00:29:00.001+09:00</published><updated>2008-01-18T00:29:28.460+09:00</updated><title type='text'>README.txt</title><content type='html'>メモを書いたのにそれをなくすというのがよくある。&lt;br&gt;だから、思いつくままにメモを書くのはもちろん大事なのだけど、しまう場所も大体きめておく。&lt;p&gt;そのひとつは、README.txt。作業フォルダひとつづつにできる限りREADME.txt&lt;br&gt;を作って、どんな意図でこの作業をしているのかを書き残す、または随時更新することにする。&lt;br&gt;作業時間が寸断されていたりすると、このディレクトリは何のために掘ったっけ、ということさえ忘れていったりする。誰の依頼で何をどうしようとしているのか、とかそんなあたりから。&lt;br&gt;ちょっと慣れた人なら、必ずREADME.txtには目を通すはずだから、引継ぎ事項のうちいくつかはこういうところにも残す。人から引き継いだものとかにそれがなければ、自分自身でディレクトリ内にREADME.txtを足したりするときもある。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1385703033914536586?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1385703033914536586/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1385703033914536586' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1385703033914536586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1385703033914536586'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/01/readmetxt.html' title='README.txt'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1771835658885827884</id><published>2008-01-05T23:44:00.000+09:00</published><updated>2008-01-27T22:09:31.719+09:00</updated><title type='text'>テンプレートを使いたい</title><content type='html'>話の流れが前後することになるが、現在pythonをうまく仕事で実用的に使ってやろうと試行錯誤している。&lt;br /&gt;&lt;br /&gt;今は、python製のWebアプリ構築用ライブラリであるDjangoを勉強している、というか眺めたりいじったりしている。&lt;br /&gt;DjangoのO/RマッパーやURLディスパッチャについても面白いと思っているが、今のところWebアプリを実際に作るような用事はないから、Djangoのテンプレートサブシステムだけを仕事で使い始めてみようかというところ。&lt;br /&gt;&lt;br /&gt;とりあえず、ごく原始的なサンプルをメモまでに：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;from django.conf import settings&lt;br /&gt;#settings.configure(TEMPLATE_DEBUG=True, TEMPLATE_DIRS=('.'))&lt;br /&gt;settings.configure()&lt;br /&gt;from django.template import Context, Template&lt;br /&gt;&lt;br /&gt;t = Template("Hello, {{ yourname }}.")&lt;br /&gt;x = {"yourname": "harry"}&lt;br /&gt;print t.render(Context(x))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;django.templateをインポートする前に、settings.configure()をあらかじめ呼んでおくのがミソ。テンプレートをファイルに格納していない限りは、何の引数も与えなくてもこれだけで一応動作する。&lt;br /&gt;&lt;br /&gt;テンプレートだけのためにDjangoを導入するのはオーバースペックではある。でも、Djangoは結構息の長いプロジェクトになるだろうという予感があるので、詳しくなっておいて損はないんじゃないかなあと思って。&lt;br /&gt;&lt;br /&gt;perlでHTML::Templateを使ってた経験が結構長いんだけど、どうにもスクリプトが汚くなってしまいがちなのに悩んでいたところでもある。リファレンスとかデリファレンスとか、無名ハッシュとか、なんかなあ。今の仕事に後任者がいるとして、あとで悩ませることが少ないソリューションをできるだけ残していきたい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1771835658885827884?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1771835658885827884/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1771835658885827884' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1771835658885827884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1771835658885827884'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2008/01/blog-post.html' title='テンプレートを使いたい'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7543811398323928086</id><published>2007-12-31T23:42:00.001+09:00</published><updated>2007-12-31T23:42:52.368+09:00</updated><title type='text'>メモを作る</title><content type='html'>記憶力が、以前と比べるとやや落ちているのではないかと考えてしまうときがある。テストなどではそういったことはないが、やるつもりだった仕事が抜け落ちることがあるせいだ。自分では、これはまだ「衰え」ではないと思っている。要求される仕事量が込み入ったものになることが増え、より複雑な記憶が必要になってしまったせいだろう。&lt;p&gt;とても当たり前のことではあるが、メモを作るということが極めて重要なことがそのあたりからわかってきた。メモを作るということは、自分にとっては、それを忘れてもよい状態になるということだ。うまくメモをまとめて管理することがうまくなるほど、自分の脳みそは楽になる。&lt;p&gt;もっと楽したい。この動機から、メモをどういうルールで書いてどうやって管理するのかということに強い興味をもつことになった。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7543811398323928086?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7543811398323928086/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7543811398323928086' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7543811398323928086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7543811398323928086'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_31.html' title='メモを作る'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-225253923202687406</id><published>2007-12-28T20:27:00.001+09:00</published><updated>2007-12-28T20:27:49.297+09:00</updated><title type='text'>担当者用か自分用か</title><content type='html'>仕事用のスクリプトを書くとき、これを使うのが自分（システム管理者）であるか、それ以外の業務担当者であるかを意識する。&lt;br&gt;自分のためのものなら、とりあえずでも動くものなら用事はこなせるが、他人、とくにコンピュータに詳しくない他人が使うことが想定される場合は、なるべくきっちりと対話式に動かせるように書く。&lt;br&gt;ドキュメントの書き方も少し違ってくる。自分用のものなら、技術上の側面を主に書いて、他人用のものなら、起こることを順番に記述する方針で書く。イレギュラーなことが起こったときだけはシステム管理者に連絡できるようにしておけばよい。&lt;br&gt;実際には、他人用ドキュメントにも、最後の章あたりを割り当てて技術メモを書いておくよう心がけている。これのコピーを携えてシス管に泣きついてくるのが通常のパターンなので、そのときすぐ見られる場所に情報を書いておくっていうこと。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-225253923202687406?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/225253923202687406/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=225253923202687406' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/225253923202687406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/225253923202687406'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_28.html' title='担当者用か自分用か'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1848713469649510544</id><published>2007-12-27T23:11:00.001+09:00</published><updated>2007-12-27T23:11:21.545+09:00</updated><title type='text'>部品の完成度を上げておく</title><content type='html'>やや大がかりな目的のためにプログラムを組むときは、それらの部品になるものから手をつけていき、その部品の完成度を上げることになるべくたくさんの努力を費やす。&lt;br&gt;それで、その部品を扱うことに安心感を持てると思う程度になったら、それらを次に組み立てて実際の仕事をする。&lt;br&gt;これがうまくいくと、安定した足場の上にいる気分で仕事ができます。これをうまくやれないと、組んだプログラムがまともに動かないことが増えて嫌になってきます。&lt;br&gt;安定した部品は自分用ライブラリとしてとっておき、必要に応じて引っ張り出して再利用すれば楽ができます。&lt;p&gt;僕自身はまだ自分のコードを再利用するのがあまりうまくないと感じていますが、もっとうまくやれるようになって、一度書いたことのある仕事はもう改めて書くまでもないくらいになりたいものです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1848713469649510544?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1848713469649510544/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1848713469649510544' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1848713469649510544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1848713469649510544'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_27.html' title='部品の完成度を上げておく'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8174798570780072689</id><published>2007-12-25T11:19:00.001+09:00</published><updated>2007-12-25T11:19:55.401+09:00</updated><title type='text'>スクリプト言語で十分</title><content type='html'>プログラムを書くというとC言語とかJavaとかそんなのを連想しがちだけど、もっとお手軽なスクリプト系でほとんどの場合十分です。もちろん仕事の種類によるんでしょうけど、たとえばシステム管理みたいな仕事では特にそうだと思います。&lt;br&gt;ここでスクリプト系ってのは、明示的なコンパイルの必要がない言語、って程度の意味で言っています。perl、python、VBscript、シェルスクリプト、そんな感じの。&lt;br&gt;スクリプト系言語は、書いて即実行してみて、手直ししてまた実行、というサイクルが短いので、楽に開発ができます。楽するために生まれた言語なんだから当たり前ですけど。&lt;br&gt;スクリプト系言語の弱点があるとすれば、「遅さ」がその最たるものじゃないかと思います。でも最近のコンピュータは動作がすごく速くなってますから、ちっとも問題になりません。仕事が遅くなるから思い切ってC言語で書き直しちゃおうか、と考えたことは一度もありません。それに、例えばネットワークがからむような仕事なら、一番遅い部分はコンピュータの処理速度よりそっちですから、何で書こうが同じですし。&lt;p&gt;「速さ」が問題にならないからには、やっぱり「楽さ」を基準に普段使いの言語を決めます。&lt;p&gt;大体C言語はとっても面倒です。Cマスター達には笑われるでしょうが、そんなレベルにはないんだから仕方ないです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8174798570780072689?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8174798570780072689/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8174798570780072689' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8174798570780072689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8174798570780072689'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_8360.html' title='スクリプト言語で十分'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-8630980955443262170</id><published>2007-12-25T09:50:00.001+09:00</published><updated>2007-12-25T09:50:31.441+09:00</updated><title type='text'>プログラマの美徳</title><content type='html'>知っている人には有名なものですが、プログラマの第一の美徳は怠惰(laziness)だと言われています。perlの作者の言葉ですが。&lt;br&gt;プログラムを組む理由は、少なくとも仕事においては、何らかの楽をするためです。大量の決まりきった仕事、手順の込み入った仕事、正確さに気をつかう仕事、そんなものを自動的にやらせるためにプログラムを組みます。&lt;br&gt;人力で無理にやったって、できるにはできることばかりなんですよ。もっと極端に言えば、コンピュータにできる仕事で、人間にできないことはないです。効率の問題です。&lt;br&gt;プログラムを書くのは、自分の小さな分身を作ることに似ている気がします。分身でなくても、小人さん、使い魔、バイト君、なんと呼んでもいいですけど、それはあらかじめ与えられた指示を忠実に実行するシモベで、そいつがお決まりの仕事を片付けてくれるから主人がその分楽できます。&lt;br&gt;より複雑なプログラムが組めるようになれば、より臨機応変で優秀な分身君を使えるようになるわけです。だからプログラマは腕を磨きます。楽するために苦労するんです。&lt;p&gt;プログラムを書けない人もプログラムを書けるようになってみたくなりませんか？なりたいでしょう。あなたがプログラムを書いてくれれば、その分僕が楽できます。どうぞよろしく。どうすればプログラムが書けるようになるのか、それはいつか考えて述べてみたいです。&lt;p&gt;ところで「怠惰」の別の側面として、何度も同じ質問に答えなくてよいように、良いドキュメントを残そうとするということがあります。こっちは忘れる人が多いんだよな…がんばります。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-8630980955443262170?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/8630980955443262170/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=8630980955443262170' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8630980955443262170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/8630980955443262170'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_25.html' title='プログラマの美徳'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-5363016936273027643</id><published>2007-12-24T21:49:00.000+09:00</published><updated>2007-12-24T21:50:47.881+09:00</updated><title type='text'>そこにある言語を使う</title><content type='html'>作業する環境は、自分の選択の余地がないときがある。&lt;br /&gt;rubyをちょっと触ってみたら面白かったので、これから仕事用のスクリプトをrubyで書いてみようとしたとする。でも今の環境にはrubyがない、または満足なバージョンのものがない。それならサッサとあきらめて、そこで使えるperlかなんかを使う。&lt;br /&gt;perlならperlで、何か特別な追加モジュールがあると便利なことがわかっていても、導入する前には本当に必要かを考え抜く。単に外部コマンドの出力を取り込んだりして済むのなら、そっちを優先する。稼動中のシステムに余分な要素が混入するのを極力避けたいから。ここらへんもKISSの原則だと思う。&lt;br /&gt;&lt;br /&gt;これでもたいていの場合ちゃんと仕事になる。&lt;br /&gt;&lt;br /&gt;そんな理由で、どんな環境でも「つぶし」の利くスクリプト言語として、今までperlに習熟してきた。サーバー上でもPC上でも、これひとつでどうにかなる。&lt;br /&gt;でもそろそろ、pythonなんかを使っても大丈夫な気がしてきた。機種更新のときには、配布クライアントにperlだけでなくpythonをインストールするようにしておいてもよいかと思う。実際のところ、python好きなんだ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-5363016936273027643?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/5363016936273027643/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=5363016936273027643' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5363016936273027643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/5363016936273027643'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_5748.html' title='そこにある言語を使う'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-7481489369888589002</id><published>2007-12-24T00:06:00.000+09:00</published><updated>2007-12-24T00:09:36.478+09:00</updated><title type='text'>KISSの原則</title><content type='html'>システム管理をやっていて究極の願いは、「安定しますように」ということだと思う。&lt;br /&gt;開発側だって同じに決まってるだろうけど。&lt;br /&gt;&lt;br /&gt;変な不具合が出ませんように。スピードが極端に落ちませんように。&lt;br /&gt;夜間バッチが朝までかかって業務が開始できなくなりませんように。&lt;br /&gt;&lt;br /&gt;システムが安定するのに一番大事なことのひとつは、それがシンプルなことだろう。&lt;br /&gt;KISSの原則とは、Keep It Simple, Stupid（単純なままにしとけ、バカ）を縮めたもので、これがシステムを設計する、または実装する際の重要な指針になる。迷ったら単純な解法を選んでおけば、たぶんそっちが正しい。複雑な工夫をシステム中に持ち込むと、その場では気の利いた感じがしたとしても、システムはきっと不安定になる。&lt;br /&gt;発注する側は要求した仕様どおり作ってもらって満足だろうけど、それはバグが多いよ。&lt;br /&gt;あとで結局改修の手間がかかって余計な損するよ。&lt;br /&gt;または、ちょっとした手直しができなくなって、結果としてシステムが業務の実情を反映できなくなるよ。&lt;br /&gt;または、担当者が変わったときなんかに、訳のわからないブラックボックスとしてしか扱えなくなるよ。ブラックボックスになると、マニュアルとほんの少し違う操作をする工夫もできなくなって、すごくストレスを抱えながらシステムを使う羽目になるよ。&lt;br /&gt;&lt;br /&gt;KISSの原則を守れなくなるのは専ら「作らせる」ほうだけど、その原因はコンピュータが魔法の道具だと思ってるからだと思う。SEさん達は魔法使いで、望みをなんでもかなえてくれる。（で、不具合を出したらそれを無限に修正してくれる。）&lt;br /&gt;そんなわけないのに。&lt;br /&gt;&lt;br /&gt;ところで筆者は、'KISS'の解釈は、Keep It Simple and Stupid（単純でバカな状態にしろ）とするほうが好きです。バカというか、愚直なシステム。そのほうが、使う側で色々と工夫ができてよいです。「馬鹿とハサミは使いよう」なんて言葉もあるし。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-7481489369888589002?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/7481489369888589002/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=7481489369888589002' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7481489369888589002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/7481489369888589002'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/kiss.html' title='KISSの原則'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1741619866690106180</id><published>2007-12-22T21:53:00.000+09:00</published><updated>2007-12-22T22:22:42.518+09:00</updated><title type='text'>社内SE</title><content type='html'>開発会社でシステムを作っているときは、社内SEという立場の仕事に興味を持っていた。&lt;br /&gt;あまり根拠があっての考えではないが、なんか社内SEって楽なのかな？って感じで。&lt;br /&gt;だって、さすがに本職のSEほど過酷じゃないだろう…&lt;br /&gt;&lt;br /&gt;で、現在の自分は、奇しくもその社内SEといってよい。なんだ大変じゃないか、この仕事も。&lt;br /&gt;たくさんあってなお増えるコンピュータを相手に走り回る。品質の悪いシステムのお守りで頭を抱える。よく変わる環境にあわせて、前任者の書いた変な管理スクリプトを書きなおさせられる。一から書き直すほうが楽だったものも多数ある。（もちろん前任を責めるものではない。僕の書くスクリプトだって、別の人が見たら変なものに決まっている）&lt;br /&gt;プリンタだの無線LANだのと、内輪からの無理難題をさばいて、やっとできた余り時間はよくわからないミーティングと書類作成に消える。&lt;br /&gt;忙しい上に、求められる知識はオールアラウンド。&lt;br /&gt;こういう状況はなんとかしなくてはなあと、いつも強く思う。どういう種類の「なんとか」なのかは、また追々。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1741619866690106180?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1741619866690106180/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1741619866690106180' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1741619866690106180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1741619866690106180'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/se.html' title='社内SE'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-4449800288536382367</id><published>2007-12-22T20:05:00.000+09:00</published><updated>2007-12-22T20:33:44.898+09:00</updated><title type='text'>昔受注者、今発注者</title><content type='html'>以前システム開発の仕事をしていたことがある。&lt;br /&gt;中小企業と呼べる程度の規模の会社だった。そこで色々な仕事をさせられて勉強したのが貴重な経験だった。時にはクライアントや上司からずいぶん無茶な要求を突きつけられたりして怒りを感じることもあった。発注者というのはなんと勝手なものだろうと思ったりした。&lt;br /&gt;あれから数回の転職を経て、偶然ながら、今はシステム開発を発注する立場にいる。こちらの側に立ってみると、今度は発注した相手からロクでもないシステムを納入されて怒りを感じることになった。&lt;br /&gt;どちら側に立っても損をした気分で腹を立てているのはどういうことだろう。片方の側にしかいたことがないのなら、相手側がなにかしら不誠実なせいだと思うところだが、自分の経験では、システムを開発するほうにしても発注するほうにしてもそれなりに誠実にやっていたと思う。なのに、win-winどころか、lose-loseな感じにさえなりかねないのはなんでだろう。&lt;br /&gt;考えているところは色々あるが、そのうち述べていくかも知れない。&lt;br /&gt;&lt;br /&gt;発注側の悩みとして、田邊氏の記事にある内容に全面的に共感している。発注側が、システムを開発するということについて知識が足りないときは、相当の確かさで悲劇的なことが起こる。&lt;br /&gt;&lt;br /&gt;田邊稔. &lt;a href="http://www.dap.ndl.go.jp/ca/modules/ca/item.php?itemid=1081"&gt;打破！変わらない組織と動かないシステム～パイレーツ・オブ・ライブラリアンを目指して～&lt;/a&gt;. カレントアウェアネス. (294), 2007, p.7-10.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-4449800288536382367?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/4449800288536382367/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=4449800288536382367' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4449800288536382367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/4449800288536382367'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post_22.html' title='昔受注者、今発注者'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2114684746269128159.post-1344812999428250936</id><published>2007-12-21T18:34:00.000+09:00</published><updated>2007-12-21T18:35:59.681+09:00</updated><title type='text'>残高照会メモ</title><content type='html'>メモでも残しておこうと思った。&lt;br /&gt;&lt;br /&gt;ブログのタイトルには特に意味はないです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2114684746269128159-1344812999428250936?l=kyujobukuro.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kyujobukuro.blogspot.com/feeds/1344812999428250936/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2114684746269128159&amp;postID=1344812999428250936' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1344812999428250936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2114684746269128159/posts/default/1344812999428250936'/><link rel='alternate' type='text/html' href='http://kyujobukuro.blogspot.com/2007/12/blog-post.html' title='残高照会メモ'/><author><name>yamamototetsuya</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://1.bp.blogspot.com/_Zi6PKIg2V_I/SxB6e7kvAhI/AAAAAAAAA68/uF2Movnk-34/S220/haniwadog.jpg'/></author><thr:total>0</thr:total></entry></feed>
