リスト内包表記について
いまさらリスト内包表記かよって言われそうだけど、まぁなんどおさらいしたっていいじゃない。という訳で下記のような事がやりたいとする。
- カンマ区切りの数字の列を文字列として受け取る(50,100,150,200,250)
- その文字列をカンマで分割してリストにする
- リストの各要素をint型にキャストする
- 最終的にリストをtuple型にキャストする
''50,100,150,200,250" ↓変換 (50, 100, 150, 200, 250)
1. ベタにやってみる。
ベタな感じやってみるとこうなる
#!/usr/bin/env python #-*- coding:utf8 -*- num_str = '50,100,150,200,250' num_list = [] for n in num_str.split(','): num_list.append(int(n)) print tuple(num_list) #=> (50, 100, 150, 200, 250)
2. リスト内包表記でやってみる。
上のでも大した行数ではないけど、リスト内包表記を使う事でより簡潔にかける!
#!/usr/bin/env python #-*- coding:utf8 -*- num_str = '50,100,150,200,250' print tuple([int(n) for n in num_str.split(',')]) #=> (50, 100, 150, 200, 250)
3. リスト内包表記の方がパフォーマンスが良い。
エキスパートPythonとか、初めてのPython(オライリー本)にも書いてあったけど、リスト内包表記の方が、往々にしてパフォーマンスが良いとされている。実際に上の二つを比較してみる。
こういう小さいコードの計測する時にはtimeitというモジュールを使うといいらしい。
#!/usr/bin/env python #-*- coding:utf8 -*- import timeit setup = """ num_str = '50,100,150,200,250' def num_str_to_tuple(): num_list = [] for n in num_str.split(','): num_list.append(int(n)) return tuple(num_list) """ stmt = "num_str_to_tuple()" t = timeit.Timer(stmt=stmt, setup=setup) print t.timeit(2000000) setup = """ num_str = '50,100,150,200,250' def num_str_to_tuple(): return tuple([int(n) for n in num_str.split(',')]) """ stmt = "num_str_to_tuple()" t = timeit.Timer(stmt=stmt, setup=setup) print t.timeit(2000000)
リスト内包表記のパフォーマンスがいいからといって今回の例だと、あまりに例がシンプルすぎて差がわかりずらいので、あえて実行回数を多めにしている。
手元の環境で上記計測コードを実行すると。こんな感じ
14.5897488594 #リスト内包表記を使ってない 13.1452250481 #リスト内包表記を使ってる
200まんかいずつ繰り返したら一秒くらいはやくなりますた。
追記(20110916)
よく考えたら、上の計測のヤツは、num_str のカンマで区切られた要素数が、多いほど、差が顕著にでるような気がしたので下記のようにしてみた。
#!/usr/bin/env python #-*- coding:utf8 -*- import timeit setup = """ num_str = ','.join([str(i) for i in range(10000000)]) def num_str_to_tuple(): num_list = [] for n in num_str.split(','): num_list.append(int(n)) return tuple(num_list) """ stmt = "num_str_to_tuple()" t = timeit.Timer(stmt=stmt, setup=setup) print t.timeit(1) setup = """ num_str = ','.join([str(i) for i in range(10000000)]) def num_str_to_tuple(): return tuple([int(n) for n in num_str.split(',')]) """ stmt = "num_str_to_tuple()" t = timeit.Timer(stmt=stmt, setup=setup) print t.timeit(1)
結果はこんな感じ
12.9693031311 #リスト内包表記を使ってない 11.8190917969 #リスト内包表記を使ってる
あんま上の計測のヤツと変わりませんでした。。。
参考
- 作者: Mark Lutz,夏目大
- 出版社/メーカー: オライリージャパン
- 発売日: 2009/02/26
- メディア: 大型本
- 購入: 12人 クリック: 423回
- この商品を含むブログ (133件) を見る
- 作者: Tarek Ziade,稲田直哉,渋川よしき,清水川貴之,森本哲也
- 出版社/メーカー: KADOKAWA/アスキー・メディアワークス
- 発売日: 2010/05/28
- メディア: 大型本
- 購入: 33人 クリック: 791回
- この商品を含むブログ (90件) を見る
水をぶちまけて動かなくなったHHKを復活させるたった一つの方法
よくHHKに水を盛大にぶちまけて、なんか T キーが押せないとか、Gキーが連打状態になるとか、ごくごく一般的に良くある出来事ですよね!
水を拭き取っても、どうにもならない時に解決するたった一つの方法を @feiz 先輩に教えてもらったので紹介するよ!みんなこれをやれば大丈夫だよ!
その名も
「The 天日干し」
なんかもうアレですよ。たかだか水こぼした位で、
このザマだよ!!!!!!
けど嘘かと思うかもしれないけど、天日干ししたら復活したんだよ!なんていうか、日本人の古き良き知恵ってやつぁ偉大だなぁとおもったよ!みんなやってみるといいよ!
お詫び
本記事は、書き手の思い込みにより書かれているため、天日干しをしたからといって必ずしも復活しない可能性は多分にあります。本件に関して、私は一切責任を追う事をできませんので、予めご了承ください。故障したらちゃんとサポートに問い合わせる事を強く強く推奨します。
HTMLメールとテキストメール を両方同時に送る(Flask-Mail)
こんばんは。そろそろブログを書かないと、またどんどん忘れるだけなのでメモをちゃんと残そうかと思います。
一昔前だとHTMLメールってうざいよねぇwww。みたいに思っていたんですが、TwitterやらFacebookやら軒並み最近のWebサービスはHTMLメールを送ってくるようになったと感じています。でどんな感じで送ってるのか見てみたら、Content-Typeに「multipart/altnative」という見慣れないやつを使ってました。
「multipart/altnative」とは何ぞやといういうのは上記リンクを見てもらえればなんとなく分かると思うのですが、誤解を恐れずに端的に言うと「HTMLとテキスト、両パターン送っとくから、メーラのお前は表示できる方表示しろや」という事です。
最近 送られてくるHTMLメールのContent-Typeを見ると、大体これになってる事が多いですね。最近とか言いつつ僕が知らなかっただけで常套手段なのかもしれませんが。
1. Flask-Mail
で Flaskでどうやってその multipart/altnative のメールを送るのかについてですが、
flask-mail — Flask-Mail v0.2 documentation
Flask-Mailという extension があるのでそれを入れればできます。
from flaskext.mail import Message msg = Message(subject, sender=sender, recipients=reciepients) msg.body = body msg.html = html_body mail.send(msg)
こんな感じ、body と html というプロパティが分かれていて、両方に値がセットされていると、勝手に 「multipart/altnative 」にして送ってくれます。楽ですね。もちろん片方しか値がセットされない場合には、text/plain or text/html になります。
余談
Flask の extensionは大体、他のPYPIパッケージのラッパー的なものが多いのですが、Flask-Mailも MailResponseを構築する部分は、lamson.mail とかいうのを使ってました。
「Lamson's goal is to put an end to the hell that is "e-mail application development". 」なんて強気な事が書いてあるので、Eメールを送るアプリケーションを開発する時とかには、利用を検討してみても良いかもですね。
以上おわり。
vimでPythonコードの折りたたみ
vimでPHP開発していた時は、良くvim の 折りたたみ機能を使ってました。
理由としては、割とメソッドを移動したりするのが楽だったり(折りたたみしてる所は yy , dd でヤンクできるから)、メソッド、クラス単位で折りたたみされてるので、俯瞰してそのファイルを眺める事ができるから、不要なメソッドとかを見つけやすかったからです。
折りたたみは最初、開けたり閉じたりするのが面倒だったんですが、気がつけば、小指が za を押すのに慣れてしまいました
といわけで、そろそろPythonのヤツも欲しいなと思ったので、プラグインを探しました。割合古いものですが、見やすいので大分気に入っています。
python_fold - Folding expression for python : vim online
これを ~/.vim/plugin の下に設置すればそれでおkです。
簡単な使い方
たとえば こんなソースがあるとします。
#!/usr/bin/env python #-*- coding:utf8 -*- class TestClass(object): """ TestClass だよ python_fold.vimの折りたたみの仕方を確認 """ _name = None def __init__(self, name = None): """ クラスの初期化 """ if name: self._name = name def hello(self): """ 挨拶する 名前がセットされていなければ helloとだけ表示される """ print 'Hey! My name is ' + self._name if self._name else 'Hello!' def say_hello(name=None): """ TestClassをインスタンス化してhelloする """ test = TestClass(name) test.hello() if __name__ == '__main__': say_hello('hoge') #=> Hey! My name is hoge say_hello() #=> Hello!
これをpython_fold.vimを導入した後だとファイルを開いた直後はこうなります。
#!/usr/bin/env python #-*- coding:utf8 -*- 17 lines: class TestClass(object): TestClass だよ ------------------------------------------------- 4 lines: def say_hello(name=None): TestClassをインスタンス化してhelloする ------------------------- if __name__ == '__main__': say_hello('hoge') #=> Hey! My name is hoge say_hello() #=> Hello!
クラスと、関数がfoldされているのが分かると思います。これを開くときは、そのラインにいって、 za を素早く押せば開きます。閉じる時もzaです。TestClassを開くとこんな感じになります。
#!/usr/bin/env python #-*- coding:utf8 -*- class TestClass(object): """ TestClass だよ python_fold.vimの折りたたみの仕方を確認 """ _name = None 4 lines: def __init__(self, name = None): クラスの初期化 -------------------------------------------------- 6 lines: def hello(self): 挨拶する ---------------------------------------------------------------------- 4 lines: def say_hello(name=None): TestClassをインスタンス化してhelloする ------------------------- if __name__ == '__main__': say_hello('hoge') #=> Hey! My name is hoge say_hello() #=> Hello!
このプラグインが良いなーと思ったのは、クラス宣言、メソッド宣言直後のdocstringの最初の一行を、foldした時に右側に表示してくれる所です。なので一行目のdocstringはなるべく簡潔な説明を書くようにしてます。
なんか上のソースだと折りたたみされている様子が分かりずらいですね。こんな風になります。
gzip 圧縮したファイルを作る
gzip圧縮したファイル作るのが簡単すぎてちょっと感動したわ。with文をサポートしてるから、ファイルクローズしてくれるし。
#!/usr/bin/env python #-*- coding:utf8 -*- import gzip filepath = 'hogehoge.txt.gz' with gzip.open(filepath, mode='wb') as gz_file: gz_file.write('hogehoge')
Lokka を heroku で なにも考えずにセットアップしてみる
最近 はやりの heroku
Cloud Application Platform | Heroku
そのherokuでも動いちゃうクラウド専用のCMS Lokka
この組み合わせを何も考えずにやりたい人向けのセットアップスクリプトを書きました。そもそもLokkaのインストールは、書く必要もないくらい簡単だけど勢い余って書いておきます。すいません、MacOSX(snow leopard)環境でしか確認してないです。Windowsではこの方法は使えません。
0. 必要なもの
- git
- bash
2. アプリの名前を決める
アプリの名前を決めませう。heroku.comのサブドメインになります。
[app_name].heroku.com
[app_name] にあたる名前を決めてください。他の人が使ってたりすると、アプリ作れないので気をつけてください。
3. インストール
名前きめました?じゃあ作業用のディレクトリを適当にターミナル開いて作って入ってください。
mkdir heroku_work cd heroku_work
ではインストール開始。下記順番でコマンド叩いてください。[app_name]は2で決めた名前に置き換えてください。
curl -O https://raw.github.com/gist/1114155/ad5fa494517e30d4b6bbb9e60686f845dcba81e5/herokka1.sh curl -O https://raw.github.com/gist/1114170/46e4fe2fb3380ab07932c916c40c56a5bf31bd06/herokka2.sh sh herokka1.sh [app_name] gemset use [app_name] sh herokka2.sh [app_name]
途中で下記のようになると思います。
- herokuに登録したメアドとパスを聞かれる -> 入力してください
- ssh認証についてyes or no 的な事が聞かれる -> yes と打ってください
問題なく最後までいけば、勝手にブラウザで[app_name].heroku.com が開いて、素敵なLokka生活のスタートです。
Lokkaを本格的に使いたい人は、デフォルトでテストユーザーが登録されているので、自分のアカウントを作って、テストユーザーは消しちゃった方が良いですよ。
備考というか謝罪
- なんで2ファイルあんの? -> gemset use が shellの中でなんか有効になりませんでした。。
- 毎回 rvm をinstallしちゃいます。。
- .bashrc の ファイルの末尾にrvmの設定追加しちゃってます。。。
- rvm でruby1.9.2 がinstallされます。特に意味はありません。
- rvm で [app_name]のgemsetを作ってつかいます。
- gem で heroku と bundler をインストールします。
余談
rvm と gemset を使ったら、pythonのvirtualenv的な事が出来ると思って喜んでいたんですが、割とrvmは不安定らしいので、気をつけてください。
ご利用に際しては、何か不具合があっても責任を取れませんのであしからず。
Let's Enjoy Lokka on Heroku!
リストから任意の数の要素をランダムに且つ重複なしで抽出したい
なんか暑すぎて、ほげーとプログラム書いてたら、なんだか 簡単な問題もスマートにやれない僕がいたのでメモ。
問題
問題はいたって簡単。 リストから任意の数の要素を、ランダムに抽出。要素は重複してはならない。簡便化するために、元のリストは要素に重複が無い事を前提とする。
[1, 2, 3, 4, 5] ↓ 3つ抽出するとする [1, 3, 5] => ok [1, 3, 3] => ng 値が重複している 当然、任意の数(ここでは3)以上の要素が存在していたら、任意の数だけ要素を返すの必須。
こんな風に考えた。
そういば、randomモジュールに 「random.choice」とかいうのがあったなーあれ使えば一発かぁとか思ったけど、そうでもなかった
- random.choice は リストからランダムに一つの要素しか返さない。
- 結果のリストには要素の重複は認められない。
なので、最初もうほげーとやってたから、ループで回して、choiceした要素が、結果のリストになければ、カウントアップしてカウントアップした結果が、任意の数に達したら、結果リスト返すでいいかと考えたけど、それって何か破綻してるなぁという事に気づいた。
なので、チョイスする回数は、任意の数とイコールなるように考えてやってみたら、なんか長ったらしくなって、もっとスマートなやり方ないかなぁ と もやもやしながらブログ書いてる。
(どうして)こうなった。
簡単に言うとこんな感じ
- ランダムで抽出
- 抽出した要素を結果リストにappend
- 抽出した要素を元リストからremove
- 任意の数の回数だけ、ループ
#!/usr/bin/env python #-*- coding:utf8 -*- import random def random_choice_unique(lists, num=4): if not lists: return [] if len(lists) <= num: return lists copy_lists = lists[:] results = [] for i in range(num): t = random.choice(copy_lists) results.append(t) copy_lists.remove(t) return results l = ['1', '2', '3', '4', '5'] print random_choice_unique(l) l = [1, 2, 3, 4, 5] print random_choice_unique(l) l = [[0, 1], [1, 2], [3, 4], [5, 6], [7, 8]] print random_choice_unique(l) l = [{'ae': 35}, {'shin': 30}, {'haru': 860}, {'key': 3}, {'easy': 1126}] print random_choice_unique(l) # remove はオブジェクトでも大丈夫。 class BuchoLover(): def __init__(self, name): self.name = name def __repr__(self): return self.name + " is a bucho lover" l = [BuchoLover(name) for name in ['ae35', 'shin', 'm_432', 'haru', 'feiz']] print random_choice_unique(l)
実行結果: http://codepad.org/8LF8wBa7
ぶっちゃけ、やりたい事はこれで、実現できるけど、もうちょっとこう、python的な感じでスマートにやれるんじゃないかなぁとか考えてる。修行足らん。
あー。七夕の時に、「#tanzaku まともにプログラムが書けるようになりたい」て書けば良かった。
関係ないけど、http://www.youtuberepeat.com/ って、youtubeに 足りない機能を、(ユーザーにとって)簡単に補完できるという意味で、なんかいいなぁと思った。
すいません。ずっと少女時代きいてました。
http://www.youtuberepeat.com/watch/?v=FJe9rIY21Yo&feature=related
追記 (20110709)
コメント欄で はたぼう先生に教えてもらいました。それ random.sample で できるよry)的なw。なんという良しなな関数w ちょっと感動した。後ちゃんとhelp読もうね > 俺
#!/usr/bin/env python #-*- coding:utf8 -*- import random def random_choice_unique(lists, num=4): if not lists: return [] if len(lists) <= num: return lists return random.sample(lists, num) l = ['1', '2', '3', '4', '5'] print random_choice_unique(l) l = [1, 2, 3, 4, 5] print random_choice_unique(l) l = [[0, 1], [1, 2], [3, 4], [5, 6], [7, 8]] print random_choice_unique(l) l = [{'ae': 35}, {'shin': 30}, {'haru': 860}, {'key': 3}, {'easy': 1126}] print random_choice_unique(l) class BuchoLover(): def __init__(self, name): self.name = name def __repr__(self): return self.name + " is a bucho lover" l = [BuchoLover(name) for name in ['ae35', 'shin', 'm_432', 'haru', 'feiz']] print random_choice_unique(l)
実行結果:http://codepad.org/AjmZyyyQ
flag_boy++