セイコガニのゆで方
初めて技術とはまったく関係の無いネタの気がする。
先週の休日にせり人となった中学からの友人にせいこがにのゆで方を教えてもらったのでメモ。
セイコガニとは?
まずセイコガニって何って人が多いと思うので前置き。
セイコガニはズワイガニとか松葉ガニと呼ばれるカニのメス。
ズワイガニは足の身がメインだけどセイコは卵や中のカニ味噌がメイン。
私の地元である福井ではセイコ、石川では香箱ガニと呼ばれている(他にもローカルな読み方があると思うけど知ってるのはこの2つ
福井、石川は時期になるとスーパーで売ってるのを見たことがあるけど、他は多分ネットでの販売とかにないと売ってないと思う。
福井ではゆでた状態で売ってるのが一般的。
カニの方
すいません、写真あr(ry
- 10分程真水につけて動かないのを確認する。
- ここで生きている状態だとゆでる時に暴れて自分の足をちぎるという恐ろしい事をするらしい
- まずはカニの殻についた泥をたわしで軽くこすって落とす。
- 卵(外子)の部分は流れない程度の弱めの流水で洗う
- この時流水で卵がふわっとするようにすると茹で上がったときの見た目と食べる時の食感がよくなるらしい
ゆでる
- 20-25分程度ゆでる
- 念の為動けないぐらいの重さの落し蓋をする(足を引きちぎらないようにする為
- 茹でる時間は殻の厚さが厚いほど長く茹でるらしいがぶっちゃけ分からん
- 目安としては泥が大量に付いていると砂地に生息していた物なので殻が薄いらしいが大量ってどれくらいよ...
- 迷ったら長めにゆでとけとのこと
食す
熱いうちに召し上がれ
Pythonのリストにおける処理パフォーマンス
twitterのTLをふと見たら[twitter:@kk6]さんが
とつぶやいていた。
個人的にはmap()関数の方が読みやすいという意見には賛成。
しかしパフォーマンスについては議論されていなかったようなので検証してみた。
とりあえずtimeit
今回はとりあえず上記にあったように整数の最小値から整数の最大値までの整数を乱数で10000個生成し、負数であったら0にして新しいリストを生成するという至って簡単な非破壊の仕様にしました。
ということで今回のパフォーマンス計測に使ったコード。
# coding:utf-8 import random import sys from timeit import Timer from itertools import imap data = [random.randint(-sys.maxint - 1, sys.maxint) for x in xrange(0, 10000)] def for_filter(): return [x if x > 0 else 0 for x in data] def map_filter(): return map(lambda x: x if x > 0 else 0, data) def imap_filter(): return [x for x in imap(lambda x: x if x > 0 else 0, data)] print Timer('for_filter()', 'from %s import data, for_filter' % __name__).timeit(10000) print Timer('map_filter()', 'from %s import data, map_filter, minus_to_zero' % __name__).timeit(10000) print Timer('imap_filter()', 'from %s import data, imap_filter, minus_to_zero' % __name__).timeit(10000)
今回測定に使ったPythonとマシンのスペック。
Python:2.7.2(MacPortsでインストールしたもの)
OS:Mac OS X 10.7.2
CPU:Core i7 2.0GHz(MBP15 early2011下位モデル)
Memory: 8GB
実行結果は
10.2765209675 17.9944810867 23.7831270695
となり、早い順にリスト内包表記, map, imapとなりました。
最初はmap()の方が早いんじゃないかと思ってたけどmap()はそんなに早くなく、
むしろリスト内包表記の方が1.8倍の速度出てます。
リスト内包表記が早い理由については、[twitter:@methane]さんが解説されている記事に詳しく載っています。
DSAS開発者の部屋:Pythonの内包表記はなぜ速い?
結論
個人的にはmap()関数の方が可読性は高いと思います。
その一方でリスト内包表記はやっぱりよいパフォーマンスでとりあえずこっち使っとけばそれなりのパフォーマンスが出ます。
以上の点を踏まえてケースバイケースで対応する方が良さそうです。
2011/10/19追記
[twitter:@kk6]さんからいただいたコメントにあるコードに合わせてみたところ結果が変わったので追記。
コードは少し端折ってます。
def for_filter(): return [x if x > 0 else 0 for x in data] def map_filter(): return map(lambda x: x if x > 0 else 0, data) def imap_filter(): return list(imap(lambda x: x if x > 0 else 0, data)) print Timer('for_filter()', 'from %s import data, for_filter' % __name__).timeit(10000) print Timer('map_filter()', 'from %s import data, map_filter' % __name__).timeit(10000) print Timer('imap_filter()', 'from %s import data, imap_filter' % __name__).timeit(10000)
そして結果は
10.1584570408 17.7165570259 16.8313369751
となり、リスト内包表記 > imap() > map()という順になりました。
早くなってる理由はリストの要素数が分かってるから最初からその要素数に合わせて領域を拡張しなくてもいいようにしてるとかそんな理由でしょうか?
kyoto.pyハンズオン参加してきた
なんか関西圏のPython関連の勉強会にいろいろ出てたらチューターの指名を頂いたので、Pythonにおけるテスト駆動開発について話してきました。
今回のハンズオンでは他に
がありました。正直チューターやらずにPyramidのハンズオン参加したかった。
TDDとPythonのテストモジュール(doctest, unittest)どっち重点的にやるかっていうのは最後まで悩んだんですが、
Pythonのテストモジュールが重点的になってしまって、TDDの内容もgdgdになってしまいどっちかにすべきだったかなあと反省しています。
私としてはdoctestとunittestをどう連携させてうまく使うかというのを説明したったのですが、上手く伝わったかどうかは非常に不安。
ここで使った資料については後日公開します。
あとLTやりましたがあまりにも突発なため資料とかが用意できず。
内容はRubyのテスティングフレームワークの充実っぷりは以前から嫉妬するほど羨ましかったので、探したらletuceというcucumberライクなBDDフレームワークがあって日本語が使えるようにしましたよと宣伝してきました。
Bazaarの部第1回反省会会場
ということで書きました。
rstで書いてたら面倒になったのでSphinxで公開しようって事になって、それならデプロイが簡単なbitbucketでという事で出来たのがこちら。
http://aroma_black.bitbucket.org/bzr-memo/build/html/bzr-hanseikai01.html
BazaarならLaunchpadでやれよってツッコミはなしの方向でお願いします。
今回は5分で分かるチュートリアルをベースに知っておくと便利そうな方法を追加して書いて行きました。
しかし、5分で分かるチュートリアルはいろいろ省略されすぎな気がします。
なので第2回もする予定。
分散型バージョン管理システム勉強会@京都参加してきた
[twitter:@naoina] さんが主催された分散型バージョン管理システム勉強会に参加してきました。
gitはこれからforkしてゴニョゴニョするのに最低限の知識は必要になるだろうし、Mercurialはイマイチ覚えきれてないし、ハンズオン形式ということで参加。
git
gitは[twitter:@__papix__]さんが講師を担当されて基本的なところをまどマギのネタが盛り込まれたスライドで説明。
6月に行われたPython京都勉強会でアニメネタは受けなかったにもかかわらずあえてそれで突っ込んだ勇気は素晴らしいと思いました。
gitはlettuce(BDDフレームワーク、Python版Cucumber)で機能拡張を行った時にすこし覚えたもののまだまだ不慣れだなとわかりました。
Bazaar
gitが早く終わったので急遽講師をやりますって返事してしまったんですが、Bazaar全然理解してなかったということが露呈してしまいました。
正直酷すぎたと思うので当日言うべきだった事をこのブログにでも書いていこうかと思います。
とりあえず新規でVCS使う場合はBazaar縛りにしよう。
Mercurial
講師は[twitter:@naoina]さん。基本的な事はほぼ網羅されていたかと思います。
Webで勉強会用に公開しているから実際にcloneして操作してみたりと実際の運用っぽい感じが出ていて完成度が高かった。
あと便利な拡張機能の紹介で知らなかった拡張としてrecordがありました。
これは部分的にコミットするツールのようで(cherry pickのコミットバージョンのような感じ)使いようによっては結構強力なツールになりそうだと思いました。
LT
LTは[twitter:@ramusara]さんと[twitter:@_likr]さん[twitter:@naoina]さんの3名。
[twitter:@ramusara]さんはgitのコミットフックを使ってJenkinsを動かすデモをされていました。コミットフックを使って何かするというのはいろいろ使われてるので今後参考にしたいです。
[twitter:@_likr]さんはMercurialのコミットフックの紹介。Mercurialは内部・外部フックとわかれていて内部フックはPythonで拡張できるという話が興味深かったです。
[twitter:@naoina]さんは勉強会前日にTwitterのTLで盛り上がった「女性が参加しやすいIT勉強会」をテーマにされていて、「参加しやすい勉強会がないなら自分で主催すればいいじゃない」的なノリがすごく面白かったです。
PythonのBDDフレームワークlettuceの日本語対応
Rubyの人気のBDDフレームワークであるcucumberをPythonにポーティングしたlettuceというライブラリを先日発見。
しかし振舞いを定義するfeatureファイルが日本語で書けず、これは頂けないということでlettuceのソースを眺めていたら簡単に追加そうだったのでforkした。
んで、pull requestを投げたところ本体にマージされたのでちょっと宣伝。
使い方
基本的な使い方は公式のページを参照してください。
ここでは主に日本語化した場合の使い方について記述します。
featureファイル
日本語でのfeatureファイルの書き方はほぼcucumberと同じです(違いについては後述)
ファイルの先頭で何の言語で書かれているかという宣言をしてください。
無い場合は自動的に推測してくれますが書いておいた方が無難だと思います。
日本語の場合だと言語コードはjaになります。
またファイルのエンコーディング指定を書く場合は1行目にファイルエンコーディングを書いて2行目にfeatureファイルの言語指定を書いてください。
以上の2つの事を踏まえて具体的なコードは以下。
# -*- coding:utf-8 -*- # language: ja
step定義ファイル
step定義ファイルでfeatureの該当行の関数を書くにはstep()デコレータを使いますが、step()デコレータの引数をユニコード文字列にしないと該当stepが無いというレポートされます。
@step("strだとステップとして検出されない") def str_is_bad(): pass @step(u"ユニコード文字列で書く") def unicode_is_good(): pass
現状の問題点
結果表示
日本語でfeatureファイルを書くと、featureファイルやstep定義ファイルの該当行表示の縦位置がそろわないという問題があります。
これはいわゆる全角文字の幅が2と数えられず、1と数えられる事に起因しています。
feature定義
Cucumberは英語のfeatureに相当する部分がフィーチャもしくは機能と両方書けますが、lettuceはフィーチャとしか書けません。
featureファイルの構文解析が対応していないっぽいことがデバッグを読んで分かったのでこちらは直り次第pull requestを投げたいと思います。
Python3.x対応
こちらは問題ではないんですがPython2.x系だとメソッド名やクラス名に日本語が使えないので各ステップのメソッド名をローマ字で書くか英語で書く必要があります。
Pythonのクラス変数とインスタンス変数の違い
動機
Pythonの言語リファレンスとか他の人のコードみてたらクラス変数とインスタンス変数の違いがよくわからなくなったのでメモ。
というか、http://d.hatena.ne.jp/Ponsuke/20090128/1233115400にインスパイアされて書きました。
今まで
自分が最初に触ったオブジェクト指向言語はJavaで、そっちの概念を引きずったままPythonをやり始めたので当然クラス変数とインスタンス変数は別々に宣言するものなんだろという考えていた。
つまり
class Hoge(object): FOO = int()
とすればクラス変数FOOが宣言されたことになりインスタンス変数は宣言されてないものだと思ってた。
そしてPythonでインスタンス変数を使うには
class Hoge(object): def __init__(self): self.FOO = int()
として、クラス変数とインスタンス変数両方使うには上の2つを組み合わせ、
class Hoge(object): FOO = int() def __init__(self): self.FOO = int()
とやるべきという認識でいた。
しかしこれが間違っていてずっとそれを使っていたのでここに記しておこうと思った。
言語仕様
Pythonの言語リファレンスを見てみると
クラス定義内で定義された変数はクラス変数です; クラス変数は全てのインスタンス間で共有されます。
とされている。
つまり
class Hoge(object): FOO = int()
このコードはクラス変数で間違いない。
さらに、
となっていて、
class Hoge(object): def __init__(self): self.FOO = int()
これで作成しているはず。
クラス変数もインスタンス変数も “self.name” 表記でアクセスすることができます。この表記でアクセスする場合、インスタンス変数は同名のクラス変数を隠蔽します。
これはコードでいうと
class Hoge(object): FOO = int() def __init__(self): self.FOO = int() def get_foo(self): return self.FOO
になって、「selfのスコープから見えるFOOがインスタンス変数のFOOだからクラス変数のFOOにはアクセスできないよ」と言ってるんだろう。
実際どうなのよ?
先人の見解を参考にしつつ自分で書いたコードが以下。
いつものようにunittestで書いてるけどassertTrueにしてみた。
若干こっちの方が見やすい気がする。
本当はdoctestの方がassert文とかなくて見やすいからいいんだろうけど、エディタのシンタックスカラーが効かなくてコードが書きにくいのでunittestにしてます。
ちなみに実行環境は
Ubuntu10.10(32bit)
Python2.6.6
です。
#! python # coding:utf-8 """クラス変数とインスタンス変数 Pythonでのクラス変数とインスタンス変数を理解する為のコード片 """ import unittest class C(object): """クラス変数FOOとインスタンス変数FOOを持つクラス""" FOO = int() def get_foo(self): """インスタンス変数FOOの取得""" return self.FOO @classmethod def get_class_foo1(cls): """クラスメソッドを使っての取得""" return cls.FOO def get_class_foo2(self): """インスタンスメソッドだがクラス変数にアクセスしているもの""" return C.FOO class D(object): """クラス変数FOOは持たないがインスタンス変数FOOを持つクラス""" def __init__(self): """コンストラクタでインスタンス変数FOOを作る""" self.FOO = int() def get_foo(self): """インスタンス変数FOOの取得""" return self.FOO class TestClassVarAndInstanceVar(unittest.TestCase): def setUp(self): C.FOO = 10 # テスト毎にクラス変数を初期化 def test_modify_instance_var_only(self): c1 = C() # インスタンス変数へセットしているはず c1.FOO = 100 self.assertTrue(hasattr(c1, "FOO")) # インスタンスにFOOはある self.assertTrue(c1.FOO == 100) # これはインスタンス変数 self.assertTrue(c1.get_foo() == 100) # メソッド経由でインスタンス変数取得 def test_class_var_access(self): c1 = C() self.assertTrue(hasattr(C, "FOO")) # クラス変数にもFOOはある self.assertTrue(C.FOO == 10) # これはクラス変数 self.assertTrue(c1.get_class_foo1() == 10) # クラスメソッドでクラス変数取得その1 self.assertTrue(c1.get_class_foo2() == 10) # クラスメソッドでクラス変数取得その2 self.assertTrue(C.get_class_foo1() == 10) # クラスメソッドでクラス変数取得その3 self.assertRaises(TypeError, C.get_class_foo2) # インスタンスメソッドの呼び出しはできない(unbound) def test_modify_class_var_and_instnce_var(self): c1 = C() c2 = C() C.FOO = 20 self.assertTrue(c1.get_class_foo1() == 20) # クラス変数は20であり c1_cls_FOO = c1.get_class_foo1() c2_cls_FOO = c2.get_class_foo1() self.assertTrue(c1_cls_FOO == c2_cls_FOO) # クラス間で共有されている c1.FOO = 100 self.assertTrue(c1.get_foo() == 100) # インスタンス変数のFOOを変更しているはず self.assertTrue(c1.get_class_foo1() != 100) # 故にクラス変数は100ではなく self.assertTrue(c1.get_class_foo1() == 20) # 20であるはず def test_class_var_not_exists(self): d = D() d.FOO = 100 self.assertTrue(hasattr(d, "FOO")) # インスタンス変数FOOはあるが self.assertTrue(not hasattr(D, "FOO")) # クラス変数の変数FOOは存在しない if __name__ == '__main__': unittest.main()
実行結果はもちろんオールグリーンですよ。
.... ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK
結論
ま、私の認識が間違っていましたってだけなんだけどね。