CodingFirst

C言語、Perl、JavaScript、最近はPythonも。出来上がったものより、プログラムを書くことが好き。あと、スイーツ。

スポンサーサイト

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Pythonでリストのソートサンプル。バイト列を数値順、多重ソートなど

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2

Pythonでリストの多重ソートを調べたのでメモ。
基本的なソートを含めてまとめておく。

リストにはsortメソッドがある。元のリストが書き換わる事に注意。

>>> lst=[3,2,1]
>>> lst.sort()
>>> lst
[1, 2, 3]

書き換えたく無い場合は、組み込み関数のsortedを使う。使い勝手はsortと同じ。

>>> lst=[3,2,1]
>>> sorted(lst)
[1, 2, 3]
>>> lst
[3, 2, 1]

逆順ソートするには、reverseか、cmpを使う。

>>> sorted([1,2,3],reverse=True)
[3, 2, 1]
>>> sorted([1,2,3],cmp=lambda x,y:cmp(y,x))
[3, 2, 1]

数値をバイト列のリストでソートすると辞書順ソートになる。

>>> sorted(['2','10','1'])
['1', '10', '2']

数値のバイト列を数値順でソートするには、cmpかkeyを使う。

>>> sorted(['2','10','1'],cmp=lambda x,y:cmp(int(x),int(y)))
['1', '2', '10']
>>> sorted(['2','10','1'],key=lambda x:int(x))
['1', '2', '10']

2次元のソート。数値や文字が組み合わさってても賢くソートしてくる

>>> sorted([[3,1],[2,2],[1,4],[1,3]])
[[1, 3], [1, 4], [2, 2], [3, 1]]
>>> sorted([[3,'a'],[2,'b'],[1,'d'],[1,'c']])
[[1, 'c'], [1, 'd'], [2, 'b'], [3, 'a']]

バイト列の数値ソートはcmpではできない事がある。その場合はkeyで。

>>> sorted([['2','a'],['10','b'],['1','d'],['1','c']],cmp=lambda x,y:cmp(int(x),int(y)))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
TypeError: int() argument must be a string or a number, not 'list'
>>> sorted([['2','a'],['10','b'],['1','d'],['1','c']],key=lambda x:[int(x[0]),x[1]])
[['1', 'c'], ['1', 'd'], ['2', 'a'], ['10', 'b']]

sortedのカスタムをするときは、cmpを使うイメージだったけど、
複雑な場合は keyでないと対応できない、むしろ、いつも key で良さそうだ。



みんなのPython 改訂版みんなのPython 改訂版
(2009/04/11)
柴田 淳

商品詳細を見る


Python クックブック 第2版Python クックブック 第2版
(2007/06/26)
Alex Martelli、Anna Martelli Ravenscroft 他

商品詳細を見る
スポンサーサイト

PythonでCookieを取得/設定する

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2

PythonのSimpleCookieを使って、Cookieの取得、設定を試した。

目的としては、
単にCGIで過去にフォームに入れた名前を取得できればよく、
それならSimpleCookieで充分っぽい。

SimpleCookieは、公式ドキュメントの
20.22. Cookie ― HTTPの状態管理 ― Python 2.6.2 documentation
を参考にした。

Pythonで書いたCookieのお試しCGIのソースコードはgistに置いた。
https://gist.github.com/956496

最初にアクセスしたときのスクリーンショット

cgi-cookie-1.png

formに"hoge"と入れてsubmitした後のスクリーンショット

cgi-cookie-2.png

実用上は下のコードにする予定。試してないけど。

#!/usr/bin/env python
import os,cgi,cgitb,Cookie; cgitb.enable()
import datetime
sc=Cookie.SimpleCookie(os.environ.get('HTTP_COOKIE',''))
expires=datetime.datetime.now()+datetime.timedelta(days=1)
name=cgi.FieldStorage().getfirst('name',
  sc.get('name').value if sc.has_key('name') else 'anon')
sc['name']=name
sc['name']["expires"]=expires.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
print "Content-Type: text/html"
print sc.output()
print """ 
<html><body><form method="post">
<input type='text' name='name' value='{0}'/>
<input type='submit' value='submit' />
</form></body></html>""".format(name)

python2.6でdictionaryをjson化した際、日本語が\uXXXXにエスケープされないようにする

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2

Python2.6でdictionaryをjson文字列化したときに
日本語が\uXXXXとUTF-16な文字列にエスケープさせないようにするのに苦労した。
(忙しい人は、最後の要するに~の部分をご参考に)

Pythonでdictionaryをファイルに読み書きするとき、
テキストファイルで一番簡単なのはJSON文字列化する手だろう。
テキストにすると、エディタで編集できるし、diffもとりやすいし、gitやsvn管理した際に履歴も追いやすい。

だけど、JSON文字列化がむずかしい。
日本語が\\uXXXXとUTF-16な文字としてエスケープされてしまう。
これだと日本語部分をエディタで編集できなくなってしまうので、
いろいろ試してみた。

まず、dictionaryをJSONで書き出して、読み込んでみる。

$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.dumps({'a':'hello'})
'{"a": "hello"}'

dictionaryをJSON文字列化するだけならすごく簡単。
だけど、日本語をまぜるとややこしくなる。

>>> json.dumps({'a':u'あああ'})
'{"a": "\\u3042\\u3042\\u3042"}'
>>> json.dumps({'a':'あああ'})
'{"a": "\\u3042\\u3042\\u3042"}'

バイト列でもユニコードでも結果は同じで、\uXXXXとUTF-16文字列化される(\が2個)。
公式サイトのドキュメントを見ると、どうやら ensure_ascii オプションの作用らしい。
19.2. json ― JSON エンコーダおよびデコーダ ― Python v2.6.2 documentation

デフォルトは、ensure_ascii=Trueなので、Falseにしてみる。

>>> json.dumps({'a':u'あああ'},ensure_ascii=False)
u'{"a": "\u3042\u3042\u3042"}'
>>> json.dumps({'a':'あああ'},ensure_ascii=False)
'{"a": "\xe3\x81\x82\xe3\x81\x82\xe3\x81\x82"}'

期待する挙動っぽいが、どう解釈するんだろ?
どちらの例もユニコード文字列化してない(\\になってない)のは期待どおり。
最初の例はJSON文字列全体をPythonユニコード文字列化してて、
次の例はJSON文字列をバイト列の文字列化している
...で、いいかな?

printしたら、ぐっとわかりやすくなるか?

>>> print json.dumps({'a':u'あああ'},ensure_ascii=False)
{"a": "あああ"}
>>> print json.dumps({'a':'あああ'},ensure_ascii=False)
{"a": "あああ"}

違いがない。余計、混乱した。

フィーリング的には違いが出そうなんだけどなぁ~。 端末がUTF-8だからかなー。

まー、いっか。
この結果は、printがなんか頑張ってたんだろうとして考えない事にする。

いよいよ、dictionaryをJSONに変換し、ファイルに書いてみる。

>>> import os
>>> f=open('out.json','w')
>>> json.dump({'a':u'あああ'},f)
>>> f.close()
>>> os.system('cat out.json')
{"a": "\u3042\u3042\u3042"}0

とりあえず、dictionaryをJSON化してファイルに書くのは簡単だし、
ファイルからJSONを読んで、dictionaryに戻すのも簡単だ。

>>> f=open('out.json','r')
>>> json.load(f)
{u'a': u'\u3042\u3042\u3042'}
>>> f.seek(0)
>>> s=json.load(f)
>>> print s['a']
あああ

便利。
あとは、書き出したファイルを日本語化するだけだ。
公式サイトでみた、ensure_ascii=False を使ってみよう。

>>> f=open('out.json','w')
>>> json.dump({'a':u'あああ'},f)
>>> f.close()
>>> json.dump({'a':u'あああ'},f,ensure_ascii=False)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.6/json/__init__.py", line 181, in dump
    fp.write(chunk)
ValueError: I/O operation on closed file

エラーになった。
公式サイトの「問題になるだろう」発言はこの事だろう。
一応、バイト列でも試してみよう。

>>> f=open('out.json','w')
>>> json.dump({'a':'あああ'},f,ensure_ascii=False)
>>> f.close()
>>> print os.system('cat out.json')
{"a": "あああ"}0

これがうまくいってしまう...やだな。
なら、dictionary内の文字列をバイト列変換してJSON化すりゃいい
...とつい考えてしまう。
バイト列でその他の処理をするのは辛そうだし...とか言って。
しかし、この方向性は捨てる。あとあと面倒な事が増えるだけだ。

ここで、公式サイトのドキュメントを思い出す。
「fp.write() が (codecs.getwriter() のように) 前もって unicode に対応していると判っているもの」
とあったので、codecs を試してみる。
けど、とりあえずバイト列で。

>>> import codecs
>>> f=codecs.open('out.json','w','utf-8')
>>> json.dump({'a':'あああ'},f,ensure_ascii=False)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.6/json/__init__.py", line 181, in dump
    fp.write(chunk)
  File "/usr/lib/python2.6/codecs.py", line 686, in write
    return self.writer.write(data)
  File "/usr/lib/python2.6/codecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 1: ordinal not in range(128)
>>> f.close()

バイト列だとエラーが出た。
バイト列内に非ASCII文字があるじゃないかと。これでいい。
では、ユニコードで試す。

>>> f=codecs.open('out.json','w','utf-8')
>>> json.dump({'a':u'あああ'},f,ensure_ascii=False)
>>> f.close()
>>> print os.system('cat out.json')
{"a": "あああ"}0

日本語で保存できた!
つまり、ユニコード文字列を含むdictionaryをエスケープせずにJSON化してファイルに書き出せた。

さて、読み込んでみる。読み込みにトラブルは無い。

>>> f=codecs.open('out.json','r','utf-8')
>>> json.load(f)
{u'a': u'\u3042\u3042\u3042'}
>>> f.seek(0)
>>> s=json.load(f)
>>> print s['a']
あああ

できたできた♪

要するに、次のように読み書きしろって事か。

>>> import json,codecs
>>> f=codecs.open('out.json','w','utf-8')
>>> json.dump({'a':u'あああ'},f,ensure_ascii=False)
>>> f=codecs.open('out.json','r','utf-8')
>>> s=json.load(f)
>>> print s['a']
あああ

これはPython2.6の例でした。
Python3.x だと文字列の取扱いが変わるらしいので、
もしかすると、もっと素直な挙動になるのかも知れない。
そうだといいな


みんなのPython 改訂版みんなのPython 改訂版
(2009/04/11)
柴田 淳

商品詳細を見る


Pythonチュートリアル 第2版Pythonチュートリアル 第2版
(2010/02/22)
Guido van Rossum

商品詳細を見る

Pythonで簡易掲示板を作った

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2

Pythonで簡易掲示板を書いた。
CGIPythonを動かし、表示側はJavaScript

まずはスクリーンショット。

mini-bbs.png

単純に文字を書き込めるだけ。
ソースコード上はスレッドとか意識して書いたけど、
UIがピンとこなかったので対応せず。

そうそう。Pythonで書く初のコードでした。
書いた感じ、すごくシンプルでとっつきやすかったんだけど、
コードをググって探すのがちと大変。
チュートリアルくらい読んでからはじめるべきかも知れない(あたりまえ?)

さて。コード的には shelveというのが特徴的だったので使ってみた。
ハッシュディクショナリを簡単に保存、読み込みができる。
これ、すごい楽でいいな。
個人的にはデータはテキストの方が好きだけど、
ぱっと何か作る時には積極的に利用すべし。

他は、リスト、ディクショナリの操作などなどで
大したことはないかな。

そうそう。JavaScriptで少し苦労した。
createElement したエレメントに onclick を設定しても呼ばれない。
これは、addEventListener()を使うのが正解らしい。こんな感じ。

var del=document.createElement('input');
del.type='button';
del.value='del';
del.addEventListener('click',(function(id){return function(){
  if(confirm("delete?")==false) return false;
  form1.q.value='del';
  form1.date.value=id;
  form1.submit();
}})(date));

作ったスクリプトは gistに置いた。
https://gist.github.com/912445


Pythonで評判が良さそうだった本をあげておく。
GAEやるようになったら買おう。




みんなのPythonみんなのPython
(2006/08/22)
柴田 淳

商品詳細を見る


初めてのPython 第3版初めてのPython 第3版
(2009/02/26)
Mark Lutz

商品詳細を見る


PythonクィックリファレンスPythonクィックリファレンス
(2004/03)
アレックス マーテリ

商品詳細を見る

 | HOME |  »

Search

Recent Entries

Foot Print



Categories

Monthly

Recent Comments

Recent Trackbacks

Profile

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。