Pythonについて覺えたことや疑問に思ったこと、及び參考にしたリソースをメモして行く感じで。面倒なのでマーク附けは最小限に。
HTMLを處理する爲のライブラリを探してゐたら、Beautiful Soupといふものが評判良い感じだったので試してみた。
% sudo aptitude install python2.5-beautifulsoup
#!/usr/bin/python2.5 import urllib2 from BeautifulSoup import BeautifulSoup url = 'http://www.geocities.co.jp/Playtown-Spade/6501/NoaAyanoLog.html' doc = BeautifulSoup(urllib2.urlopen(url).read()) print doc
<!DOCTYPE HTML PUBLIC "ISO/IEC 15445:2000//DTD HTML//EN"> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <meta name="author" content="Takehide Nozaki" /> <link rel="stylesheet" type="text/css" href="./tnstyle.css" /> <link rel="stylesheet" type="text/css" href="./tnclass.css" /> <title>のあとあやのの愛の交換日記</title> </head> <body> <center><a href="http://chakumero.mobile.yahoo.co.jp/"><img src="http://www.geocities.jp/js_source/filler_nm.gif" border="0" /></a><br clear="all" /></center> <div class="status"> <ul class="return"> <li class="return"><a href="./">古書と古本</a></li> <li class="return"><a href="Ohkaindex.html">櫻花さん番外地</a></li> <li class="return"><a href="NoaandAyano.html">のあ&あやの</a></li> </ul> </div> <h1>のあとあやのの愛の交換日記</h1> <ul> <li>((((;゚Д゚))) ロリロリ</li> </ul> <h2>平成十五年五月十八日</h2> <dl> <dt>のあ</dt> <dd>「パワード・シーツ」つてどうかな?</dd> <dt>あやの</dt> <dd>……どうかな、つて言はれても。何の話よ?</dd> <dt>のあ</dt> <dd>變な譯語。</dd> <dt>あやの</dt> <dd>變な譯語つて……で、何の譯語?</dd> <dt>のあ</dt> <dd>一反もめん。</dd> <dt>あやの</dt> <dd>……一反もめん?</dd> </dl>
(中略)
<h2>出典</h2> <p>のあとあやのは「闇黒日記」で絶讃すごくたまに連載中です。</p> <dl> <dt><a href="http://isweb2.infoseek.co.jp/~noz/diary/">日記バックナンバー</a></dt> <dd><a href="http://members.jcom.home.ne.jp/w3c/omake/diary.html">闇黒日記</a>(最新版)</dd> </dl> </body> </html>
<br clear="all" />のやうにする。でもXHTML化する訣ではなし、XML宣言を附けるわけでも文書型宣言を取除くでもなし——といふ中途半端な「XML化」はちょっと頂けない。
<CENTER>が<center>のやうにタグ名は小文字に直される。
takkan_mのNo planな日常 - 考え方かぁに書かれてゐた次のアイディア:
15の倍数のリスト、5の倍数のリスト、3の倍数のリスト作って、そん中の要素だったら、値返してやればいいんでしょ
takkan_mのNo planな日常 - 考え方かぁ
之をヒントにしてPythonで書いてみた。
正直2分*
どころか大分梃摺ったが、最終的に出來上がったのはこれ:
def fizzbuzzsequence (fizznumber, buzznumber, first, last): # (1) result = range(first, last + 1) # (2) fizz = set(range(fizznumber, last + 1, fizznumber)) buzz = set(range(buzznumber, last + 1, buzznumber)) # (3) fizzbuzz = fizz.intersection(buzz) # (4) for i in fizz: result[i - 1] = 'Fizz' for i in buzz: result[i - 1] = 'Buzz' for i in fizzbuzz: result[i - 1] = 'FizzBuzz' return result for i in fizzbuzzsequence(3, 5, 1, 100): print i
result = range(first, last + 1)set(range(fizznumber, last + 1, fizznumber))range(n, 上限, n)といふ風にrange函數を使った。そして次の處理の爲にリストを集合型(set型)に變換。fizzbuzz = fizz.intersection(buzz)3と5両方の倍数*を得る爲に集合型のメソッドを使った。intersectionメソッドは、レシーバ及び引數のset型オブジェクトに
共通に含まれる要素を持った新しいsetを作成*する。詰り積集合を得る。
for i in fizz: result[i - 1] = 'Fizz'result)について、此等三つの集合に含まれてゐる數値 - 1番目のアイテムを、'Fizz'・'Buzz'・'FizzBuzz'のそれぞれで上書きする。setを使ふと決めてから最初に書いたヴァージョンも載せてみる。面倒なので解説は無し。
fizz = set(range(3, 101, 3)) buzz = set(range(5, 101, 5)) fizzbuzz = fizz.intersection(buzz) number = set(range(1, 101, 1)) fizz = fizz.symmetric_difference(fizzbuzz) buzz = buzz.symmetric_difference(fizzbuzz) number = number.symmetric_difference(fizz) number = number.symmetric_difference(buzz) number = number.symmetric_difference(fizzbuzz) fizz = [[i, 'Fizz'] for i in fizz] buzz = [[i, 'Buzz'] for i in buzz] fizzbuzz = [[i, 'FizzBuzz'] for i in fizzbuzz] number = [[i, str(i)] for i in number] result = number + fizz + buzz + fizzbuzz result.sort(lambda a, b: a[0] - b[0]) for i in result: print i[1]
Karetta|Gaucheプログラミング|「Lisp脳」の謎に迫る - Schemeプログラマの発想を讀んで、Pythonで同じやうにmap函數を使ったFizz-Buzzを書いてみた。
def fizzbuzz (n): if n % 3 == 0 and n % 5 == 0: return "FizzBuzz" elif n % 3 == 0: return "Fizz" elif n % 5 == 0: return "Buzz" else: return n ls = range(1, 101) print map(fizzbuzz, ls)
實行結果:
[1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz', 16, 17, 'Fizz', 19, 'Buzz', 'Fizz', 22, 23, 'Fizz', 'Buzz', 26, 'Fizz', 28, 29, 'FizzBuzz', 31, 32, 'Fizz', 34, 'Buzz', 'Fizz', 37, 38, 'Fizz', 'Buzz', 41, 'Fizz', 43, 44, 'FizzBuzz', 46, 47, 'Fizz', 49, 'Buzz', 'Fizz', 52, 53, 'Fizz', 'Buzz', 56, 'Fizz', 58, 59, 'FizzBuzz', 61, 62, 'Fizz', 64, 'Buzz', 'Fizz', 67, 68, 'Fizz', 'Buzz', 71, 'Fizz', 73, 74, 'FizzBuzz', 76, 77, 'Fizz', 79, 'Buzz', 'Fizz', 82, 83, 'Fizz', 'Buzz', 86, 'Fizz', 88, 89, 'FizzBuzz', 91, 92, 'Fizz', 94, 'Buzz', 'Fizz', 97, 98, 'Fizz', 'Buzz']
2.1 組み込み関数
- map(function, list, ...)
- function を list の全ての要素に適用し、返された値からなるリストを返します。追加の list 引数を与えた場合、 function はそれらを引数として取らなければならず、関数はそのリストの全ての要素について個別に適用されます; 他のリストより短いリストがある場合、要素 None で延長されます。function が None の場合、恒等関数であると仮定されます; すなわち、複数のリスト引数が存在する場合、map() は全てのリスト引数に対し、対応する要素からなるタプルからなるリストを返します (転置操作のようなものです)。list 引数はどのようなシーケンス型でもかまいません; 結果は常にリストになります。
1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。
どうしてプログラマに・・・プログラムが書けないのか?
for i in range(1, 101): if i % 3 == 0 and i % 5 == 0: print 'FizzBuzz' elif i % 3 == 0: print 'Fizz' elif i % 5 == 0: print 'Buzz' else: print i
「1から100迄の數を繰返す」爲にfor i in range(1,101):と書いてゐるのだが、101といふ、まるで關係無い數字が出てくるといふのは、どうなのだらう。他に手はないものかしら。
文字列に対する論理かけ算が可能*
以前、ふるごむのうんこ日記 - ファイルの中身を Unicode エスケープするに觸發されて書いたもの。公開するのを忘れてゐた。PythonといふよりEmacs Lispプログラムとしての色合ひが濃いのだけれど、まあ一往Python使ってゐるし、といふことで此處に掲載。御自由にどうぞ。
あ、さうさう、これ、タブを\tに變換してしまひます。駄目ぢゃん。なんとかしたいんだけど、自分がインデントにタブを使はない派だから放置中。
;;; my-unicode-escape.el --- EmacsのリージョンをUnicodeエスケープする ;; Copyright 2006 MORIYAMA Hiroshi <hiroshi@kvd.biglobe.ne.jp> ;; This program is free softwear. You can redistribute it and/or ;; modify it. ;;; Commentary: ;;;; これなに? ;; EmacsのバッファのリージョンをUnicodeエスケープしたりアンエスケープ ;; したりします。パスの通ったところにPythonが必要です。 ;;;; インストール ;; 1. my-unicode-escape.el といふ名前で、Emacsのload-pathが通ったとこ ;; ろに保存。 ;; 2. ~/.emacs.el (或いは ~/.emacs) に ;; (require 'my-unicode-escape) ;; と記述。 ;;;; 使用方法 ;; M-x my-unicode-escape-region でリージョンをエスケープ。 ;; 「いろは」が「\u3044\u308d\u306f」になります。 ;; M-x my-unicode-unescape-region でリージョンをアンエスケープ。 ;; 「\u3044\u308d\u306f」が「いろは」になります。 ;;;; 言ひわけとかお願ひとか ;; Emacsのcoding關連の處理が怪しいです。いまひとつ理解して切れてゐない。 ;; 一應私の環境(EUC-JP)では問題無く動いてゐるやうですが、その他の環境・ ;; 設定でのテストは殆どしてゐません。「動かない!」とか「ここはかうした ;; 方が良いよ」とかがありましたら是非おしらせください。 ;;; Code: (defun my-unicode-escape-program (&optional decode) (let ((in-coding (substring (symbol-name (cdr default-process-coding-system)) 0 (string-match "-\\(unix\\|dos\\|mac\\)" (symbol-name (cdr default-process-coding-system))))) (out-coding (substring (symbol-name (car default-process-coding-system)) 0 (string-match "-\\(unix\\|dos\\|mac\\)" (symbol-name (car default-process-coding-system)))))) (if decode ;; decode program: `("python" ;; command name or full path. ,(concat "\ import sys, re, codecs for m in re.finditer(r'(?s)(?P<escaped_string>\\\\u[0-9A-Fa-f]{4})|.', unicode(sys.stdin.read(), '" in-coding "')): if m.group('escaped_string'): es = m.group('escaped_string') try: sys.stdout.write(es.encode('ascii').decode('unicode_escape').encode('" out-coding "')) except: sys.stdout.write(es.encode('" out-coding "')) else: sys.stdout.write(m.group(0).encode('" out-coding "'))" )) ;; encode program: `("python" ;; command name or full path. ,(concat "\ import sys, re, codecs for line in sys.stdin: re_NL = re.compile(r'\\r\\n$|[\\n\\r]$') NL = re.search(re_NL, line) try: NL = NL.group(0) except: NL = '' line = re.sub(re_NL, '', line) sys.stdout.write(unicode(line, '" in-coding "').encode('unicode_escape') + NL)" ;; memo: S.encode('unicode_escape') は 改行文字もエスケープしてしまふので、 ;; 改行を變數に待避させてから變換してゐる。 ))))) (defun my-unicode-escape-or-unescape-region-program-run (start end &optional decode) (save-excursion (call-process-region start end (car (my-unicode-escape-program)) ;; program-name t ; delete: リージョンを削除するか否か t ; destination: deleteと此れが非nilの場合リージョンと出力を入換へる nil ; display "-c" (car (cdr (my-unicode-escape-program decode))) ; arguments ))) (defun my-unicode-escape-region (start end) (interactive "r") (my-unicode-escape-or-unescape-region-program-run start end)) (defun my-unicode-unescape-region (start end) (interactive "r") (my-unicode-escape-or-unescape-region-program-run start end t)) (provide 'my-unicode-escape) ;;; my-unicode-escape.el ends here
Pythonの正規表現では、グループに名前を附けてその名前で參照することが出來る:
import re
s = '2006-06-16T11:12:23.96+09:00'
re_w3cdtf = re.compile(r'(?P<year>[0-9][0-9][0-9][0-9])-'
r'(?P<month>0[1-9]|1[0-2])-'
r'(?P<day>[0-2][0-9]|3[0-2])T'
r'(?P<hour>[0-1][0-9]|2[0-3]):'
r'(?P<minute>[0-5][0-9]):'
r'(?P<second>[0-5][0-9]).'
r'(?P<microseconds>[0-9]+)'
r'(?P<tzd>Z|[-+][0-2][0-9]:[0-5][0-9])')
m = re_w3cdtf.search(s)
if m:
print m.group('year')
print m.group('month')
print m.group('day')
print m.group('hour')
print m.group('minute')
print m.group('second')
print m.group('microseconds')
print m.group('tzd')
實行結果:
2006 06 16 11 12 23 96 +09:00
(?P<name>と)で圍んだ部分が名前附きのグループ。m.group('name') のやうにして參照出來る。通常のグループのやうに整數でも參照可。
名前附きグループは正規表現が若干繁雜になる一方、 グループ參照の際の可讀性を高める效果がある。だがそれだけだったらコメントで註を附けておけば良い話だ。名前附きグループを使ふ理由としてはそれよりも、參照の際のインデックスが不變といふ效果が大きいと思はれる。つまり、正規表現にグループを追加したり削除したらグループ番號(m.group(1)の1とか)を正規表現に合せて變更しなければならない場合が多いが、名前による參照ならそのやうな手間が無い。これは結構嬉しい。
なほ通常のグループ同樣に、正規表現中や置換テキスト(re.subの第二引數など)の中でも參照出來る。(?P=name)とか\g<name>。その邊を含めた詳細については下記リンク先を參照。
Python の re モジュールを用いた、正規表現の入門者向けチュートリアル1. はじめに
Pythonのリストにはjoin()メソッドが無い。join()は文字列のメソッドとして用意されてゐる。
print '/'.join(['', 'usr', 'lib', 'python'])
上記はレシーバの文字列を區切りにして要素を連結する。以下が實行結果:
/usr/lib/python
引數はリストでなくとも良い。タプルとか文字列とか。
print '/'.join(('', 'usr', 'lib', 'python'))
print ', '.join('0123456789')
實行結果:
/usr/lib/python 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
URIエンコードとデコードにはurllibモジュールのquote()とunquote()が使へる。
# -*- coding: utf-8; -*-
import urllib
print urllib.quote('いろはにほへと')
print urllib.quote(u'いろはにほへと'.encode('euc-jp'))
print urllib.quote(u'いろはにほへと'.encode('shift_jis'))
print urllib.quote(u'いろはにほへと'.encode('iso-2022-jp'))
print urllib.quote(u'いろはにほへと')
print urllib.unquote('%E3%81%84%E3%82%8D%E3%81%AF%E3%81%AB%E3%81%BB%E3%81%B8%E3%81%A8')
實行結果:
%E3%81%84%E3%82%8D%E3%81%AF%E3%81%AB%E3%81%BB%E3%81%B8%E3%81%A8 %A4%A4%A4%ED%A4%CF%A4%CB%A4%DB%A4%D8%A4%C8 %82%A2%82%EB%82%CD%82%C9%82%D9%82%D6%82%C6 %1B%24B%24%24%24m%24O%24K%24%5B%24X%24H%1B%28B %3044%308D%306F%306B%307B%3078%3068 いろはにほへと
クエリ文字列用のエンコード・デコードにはquote_plus()とunquote_plus()。空白が+に、+が空白になる。
# -*- coding: utf-8; -*-
import urllib
print urllib.quote_plus('Python URIエンコード')
print urllib.unquote_plus('Python+URI%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89')
實行結果:
Python+URI%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89 Python URIエンコード
クエリ文字列を作るならurlencode()といふのもある。
# -*- coding: utf-8; -*-
import urllib
urlprefix = 'http://www.google.co.jp/search?'
keyword = u'Python URIエンコード'
lang = 'ja'
encoding = 'utf-8'
query = [
('q', keyword.encode(encoding)),
('hl', lang),
('lr', 'lang_' + lang),
('ie', encoding),
('oe', encoding),
]
print urlprefix + urllib.urlencode(query)
實行結果:
http://www.google.co.jp/search?q=Python+URI%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89&hl=ja&lr=lang_ja&ie=utf-8&oe=utf-8
辭書を引數にすることも出來る。ただしその場合要素(クエリ)の順番は保持されない。
# -*- coding: utf-8; -*-
import urllib
urlprefix = 'http://www.google.co.jp/search?'
keyword = u'Python URIエンコード'
lang = 'ja'
encoding = 'utf-8'
query = {
'q': keyword.encode(encoding),
'hl': lang,
'lr': 'lang_'+ lang,
'ie': encoding,
'oe': encoding,
}
print urlprefix + urllib.urlencode(query)
實行例:
http://www.google.co.jp/search?q=Python+URI%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89&ie=utf-8&oe=utf-8&lr=lang_ja&hl=ja
參考:
Rubyのdefined?のやうに、或名前が定義されてゐるかどうか調べるには?
組込み函數のvars()が使へさう。
print vars()
if not vars().has_key('f'):
def f():
pass
print vars()
實行例:
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__': 'learningpython.py', '__doc__': None}
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__': 'learningpython.py', '__doc__': None, 'f': <function f at 0x4021cd4c>}
參考:
組込みのdir()函數を引數無しで呼出すと、現在のスコープにあるオブジェクトの名前を列擧したリストを返す。
print '(1):', dir()
foo = 'FOO'
print '(2):', dir()
def bar():
localvariable = 'BAR'
return dir()
print '(3):', dir()
print '(4):', bar()
實行例:
(1): ['__builtins__', '__doc__', '__file__', '__name__'] (2): ['__builtins__', '__doc__', '__file__', '__name__', 'foo'] (3): ['__builtins__', '__doc__', '__file__', '__name__', 'bar', 'foo'] (4): ['localvariable']
引數を附けて呼出すと、その引數のオブジェクトのスコープにある名前(オブジェクトの屬性)を列擧したリストを返す。(といふ説明で合ってるかしら?)
print dir('string')
參考:
組込みの函數や定數などの名前(iter とか True とか)は引數無しのdir()の返値には含まれない。
print dir()
實行例:
['__builtins__', '__doc__', '__file__', '__name__']
その代りかどうかは知らないが、__builtins__ といふ名前がある。dir()で「中身」を見てみよう。
print dir(__builtins__)
豫想どほり組込み函數などの名前が入ったリストが得られた。……ぢゃあ、もしかして:
print __builtins__.range(10) print range is __builtins__.range
實行例:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] True
ふむふむ。普段單に iter とか range などと書いた場合、それらは實際には__builtins__.iter や __builtins__.range などを參照してゐた、といふことか。
組込み以外の名前ではどうだらうか:
__builtins__.foo = 'FOO' print foo print __builtins__.foo foo = 'BAR' print foo print __builtins__.foo
實行例:
FOO FOO BAR FOO
ほほう。つまり……定義されてゐない無い名前が使用されたときは、 __builtins__ の中にそれを探しに行くことになってゐる、といふ理解で良いのかな?
參考:
あるコードブロックの実行時に関連付けられる組み込み名前空間は、実際にはコードブロックのグローバル名前空間内に入っている名前 __builtins__ を参照する形になっています。