セイコガニのゆで方

初めて技術とはまったく関係の無いネタの気がする。
先週の休日にせり人となった中学からの友人にせいこがにのゆで方を教えてもらったのでメモ。

セイコガニとは?

まずセイコガニって何って人が多いと思うので前置き。
セイコガニはズワイガニとか松葉ガニと呼ばれるカニのメス。
ズワイガニは足の身がメインだけどセイコは卵や中のカニ味噌がメイン。

私の地元である福井ではセイコ、石川では香箱ガニと呼ばれている(他にもローカルな読み方があると思うけど知ってるのはこの2つ
福井、石川は時期になるとスーパーで売ってるのを見たことがあるけど、他は多分ネットでの販売とかにないと売ってないと思う。
福井ではゆでた状態で売ってるのが一般的。

ゆでる準備

すいません、写真ありません。

  1. 大きめの鍋にカニが十分浸かる程度の3-4%の食塩水作り沸騰させる

カニの方

すいません、写真あr(ry

  1. 10分程真水につけて動かないのを確認する。
    • ここで生きている状態だとゆでる時に暴れて自分の足をちぎるという恐ろしい事をするらしい
  2. まずはカニの殻についた泥をたわしで軽くこすって落とす。
  3. 卵(外子)の部分は流れない程度の弱めの流水で洗う
    • この時流水で卵がふわっとするようにすると茹で上がったときの見た目と食べる時の食感がよくなるらしい

ゆでる

  1. 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フレームワークがあって日本語が使えるようにしましたよと宣伝してきました。

他の参加者のレポート

kyoto.py Pythonハンズオン開催しました - 何気に大変
PyOpenCLハンズオン報告 - likr’s labo

追記:資料公開

資料以下に公開しました。
忘れていて遅れました。すみません。

http://aroma_black.bitbucket.org/kyotopy201109/

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勉強会」をテーマにされていて、「参加しやすい勉強会がないなら自分で主催すればいいじゃない」的なノリがすごく面白かったです。

その他気づいた事

当日のUstで名古屋のgitの貴公子[twitter:@bleis]さんが見ていたらしく、ところどころTwitter経由で補足しておられました。
Mercurialはこうしているけどgitではこうしている、と対比しながらの補足で自分がMercurial使いだった事もあり大変参考になりました。
補足ありがとうございました。

Bazaarの部反省会会場

ということで今週中にまず補足の1回目を書きますです。

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系だとメソッド名やクラス名に日本語が使えないので各ステップのメソッド名をローマ字で書くか英語で書く必要があります。

最後に

マスターには取り込まれたみたいですがPyPIに上がってるパッケージははてダを書いている時点では古いと思われるので作者githubから落としてsetup.py installとする方がいいかもしれません。


他に何かあったらコメントに追記してもらえれば幸いです。

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()

このコードはクラス変数で間違いない。
さらに、

インスタンス変数を作成するには、メソッドの中で self.name = value でセットできます。

となっていて、

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

結論

ま、私の認識が間違っていましたってだけなんだけどね。