Python Tips Vol.2

Vol.1が好評だったので、早速Vol.2を書いちゃった訳ではありません
単純に、また小ネタをまとめておきたいと思っただけです。
だいたいが、Vol.1が好評だったとか、何をどう解釈したらそうなるのかが不明です。
あるいは、根拠の不在が自明です。


そんなわけで、早々とこうして第2回目を開催するに至りました。
さて、記事の内容については案の定、例の如しという感じですが、敢えて時間の無駄遣いを楽しみたい方はセルフ・サービスでお願いします。
ただ、僕の個人的なお勧めは、パソコンの電源を切って寝る(プライスレス)です。
どちらがより有益な行為かなんて論争は、蛙鳴蝉噪、まさしくこの日記のようなものです。
そう言えば、ワンパターンな文体だなあとお思いでしょうが、それが僕の限界とご容赦願いたいところであります。
僭越ながら一言申し添えると、時間も有限ならば貴方の精神力も有限なのです。どうかそのことをご理解いただいて、僕に対して怒りを爆発させることのないよう、よろしくお願い申し上げます。


まあいいかげん書き飽きて、読み飽きたでしょうから、そろそろ本題に入るかもしれません。
いちいちバカ話をしなきゃ本題に入れないのかとおっしゃられても、この日記にバカ話以外の内容が記載されること自体が稀有なので、裏を返せばこの先もずっとこんな感じなので、ここまでの内容で体調あるいは機嫌が悪くなった方は、速やかにこのページを閉じられることを推奨します。
話のベクトルをねじ曲げますが、世界中に名を馳せるネズミや犬、アヒルなどが登場する、箱発の人気作と言えば鍵の剣が鍵となる物語(以下めんどいので鍵剣物語とします)と僕は思っていて、そして好きな作品でもあります。
ヘビィゲーマーという訳でもないんですが、そこそこやってます。特にやりこんだのは、某アイドルグループがやってる番組タイトルに良く似たネーミングの、もっと言うと疾走感溢れるネーミングの、ヒロインが主人公を車で引き飛ばしておいて「ごめ〜ん」とか言っちゃうアレのシリーズです。つっても、ワンツーだけですが。
スリーはせめてPSPで出すべきだと思うんだけどなあ……。
で、何の話がしたかったかと言うと、鍵剣物語で始めて3D酔いを体験したというだけのことを言いたかったんです。
何か見えたかもしれませんが、気のせいでしょう。
最初は良く分からなかったんですよね、自分が酔っているという感覚が。車酔いも酷いんですけど、あれに似た感覚だったと記憶しています。
原因はものすっごく要約すると、錯覚によるものだそうです(僕調べ)。
目の前の小さな画面には、ゲーム内でとられた広い視野角があり、まず不自然です。言ってみれば、小さな箱の中に大きな箱が入ってるようなものですからね。ただし、ここでの大小は物質的な大きさではなく、精神的なスケールだと思いますが。
加えて、現実の視点の移ろいと仮想の視点の移ろいのギャップ。これも大きな要因らしいです(何度も言うけど、僕調べ)。
そんな僕も、耐性が付いたのか、MH(マッドなヘンタイではありません)では酔いませんでした。
まあ、なんか乗り物酔いしたみたいにだるいとか思いながら、ゲームを続けた僕にはそもそも縁のない話ではありますが。
と。
やっと、閑話休題
お疲れ様でした。


今度こそ、本題。そして、本日のメニューはこちら。

  1. PythonとGIL
  2. なあんにもしない関数
  3. ドキュメンテーション文字列とは

以上の3本です。

PythonとGIL:

並列処理をしたいなあ、なんて思って色々調べていたら、驚愕の事実が判明しました。
Pythonは、スレッドを増やしても並列処理にならないんだそうです。
仮に、スレッドをいくつも走らせたところで、それらは交互に実行しあい、決して並列には処理されません。
つまり、マルチスレッドのみの並列処理では実効速度向上は望めないということです。
ここで、『のみ』としたのは、たとえばスレッドをいくつか立ち上げ、その中で処理を行うプロセスを実行すれば、速度が向上するケースもあるからです。スレッドonlyでは無理ということ自体の解決にはなりませんが。


ここで、GILについて。
GILはGlobal Interpreter Lockの略で、詳細を省いて並列処理を実現したい側の人間から簡潔に言うと、プログラムの並列性を制限してしまう排他ロックで、Python(CPython)だけでなくRubyも、言語レベルでこのように実装されています。
従って、スレッドだけで並列処理を実現し、しかも速度向上を望むとなると、Pythonだけでは無理ということになります。
まあ、それにこだわる必要もないでしょうが、そうしたくてもできないという側面を知ることができて良かったと思います。


そんな感じで。
この日記のどっかで、処理重いからスレッド使おうとか言ってた僕マジ憐れです。

2010/12/18 訂正:

上の記事で、「言語レベルで実装」とかほざいてますが、正しい表現ではないようです。
「どゆこと?」って方へ、詳細はコメントを参照して頂けると幸いです。
失礼いたしました。

なあんにもしない関数:

突然ですが、以下のコード。

#!/usr/bin/env python
def test(x):

print "hello"

これは、実行できません。エラー吐きます。

#!/usr/bin/env python
def test(x):
    x

print "hello"

とかすれば大丈夫。なんですが……
正直、気持ち悪いです。xにいてほしくなさ過ぎます。
ただ、こういう『何もしない』関数が必要になることもありますよね。特に作りかけの段階とか。
そういうときには、

#!/usr/bin/env python
def test(x):
    pass

print "hello ", test(1)

とすれば良いらしいです。これで、見事に何もしません。
ちなみに、上の実行結果は、

hello  None

です。
些細なネタですが、使いどころはあるんじゃないかと僕みたいのは思いました。

ドキュメンテーション文字列とは:

時間が経つのは早いもので、もう最後の題目です。
中身がないからとか言ってはいけないんです。
長い文章が、その長さに見合うだけの情報を持つとは限らないでしょう?この記事の前書きのように。
冗長な文章は、堅いこと書くには向かないんです。
もしかしたら、堅いこと書くのに向いてないのは僕かもしれませんが、その辺は後日に譲るとして。
ドキュメンテーション文字列ってのは、たとえば、

def vice(x):
    """
    This function is incompetence.
    """
    pass

print vice(1)

みたいに、関数とかクラスとかを定義する際に良く見かける、3つのダブルクォーテーションで囲まれた文字列のことです。
これって、本来は改行を含む文字列の記述に使う記法ではありますが、書く位置によっては違う作用をもたらします。


どういうことか。簡単な実験のために、上のコードをtest.py、次のコードをtest2.pyとでもしましょう。

def vice(x):
    pass
    """
    This function is incompetence.
    """

print vice(1)

さて、2つのファイルを作ったわけですが、ここで出てくるのがpydocコマンドです。
多くは語りませんが、たとえば以下のようになります。
test.pyがあるディレクトリにて、

% pydoc test
None
Help on module test:

NAME
    test

FILE
    /<file-path>/test.py

FUNCTIONS
    vice(x)
        This function is incompetence.

おわかりいただけますかね?pydocはこのように、Pythonモジュールの簡単なリファレンスを作ってくれます。
ちなみに、

pydoc -w test

とすると、HTMLで吐き出してくれちゃったりするらしいです。
ちなみに、test2.pyで同様にした場合の結果は、

None
Help on module test2:

NAME
    test2

FILE
    <file-path>/test2.py

FUNCTIONS
    vice(x)

です。
2つの実行結果には違いがあり、ファイル名は当然ながら、後者は説明文(This function is incompetence.)が消えています。
これが、位置による違いです。
pydocとドキュメンテーション文字列は便利だと思うので、うまく活用できたらと思った次第です。

結論:

たぶん、Vol.3もすぐに書くことになるだろうなあ。

2010/12/18 追記:

この記事が気になった方は、コメントも参照してください。