このページは Python 2.3 くらいのときに書かれたものです。
>>> fs = [ lambda: i for i in range(8) ] >>> fs[2]() 7
各 i ごとにクロージャが生成されるのではなく、ひとつのクロージャで i の値が書き換えられるため、このような結果になる。これは期待した動作ではないと思う。
同じ問題は for ループでも起こる。
>>> for i in range(8): ... fs.append( lambda: i ) ... >>> fs[2]() 7
これは、デフォルト引数をうまく使えば回避できる。
>>> fs = [ lambda i=i: i for i in range(8) ] >>> fs[2]() 2
これは Tutorial にも載っているけど。
>>> def f(xs = []): ... xs.append(0) ... print xs >>> f() [0] >>> f() [0, 0]
CPython の GC は参照カウントを主に用いているので、(循環参照が発生しなければ)ファイルのクローズなどをデストラクタに任せることができる。
>>> data = file("hoge", "r").read()
上のプログラムで、 file オブジェクトは次の行が実行される前に必ず回収され、ファイルのクローズも行われる、ということ。
最近は CPython 以外の実装も普及してきて、それらの処理系が参照カウントを使っている保証はないので、 with 文などを用いて確実にデストラクトされるようにすべきです。すいません。
デストラクタを持つオブジェクトが循環参照に含まれる場合の GC の動作は言語によってまちまちだが、 Python では原則としてそれらのオブジェクトは開放しない。回収されなかったオブジェクトは gc.garbage
に保存される。
http://www.python.jp/doc/nightly/lib/module-gc.html
>>> (-3) % 2 1 >>> 3 % (-2) -1 >>> (+1) / 3 0 >>> (-1) / 3 -1
負数に対する剰余演算の結果は C などでは環境依存で、例えば x86 (たぶんほとんどのアーキテクチャでそうなんだろうけど)なら (-3) % 2 == -1
だけど、 Python では上記のように少し気の利いた動作になっている。これと consistent なように、除算に関しても 0 に近い整数に丸められるのではなく、小さい整数に丸められる(!)。
これ、便利なことも多いのだけど、代償として、
(-a) / b != -(a / b) (-a) % b != -(a % b)
なので、気を付けるべし。怖っ。
イテレータの next()
メソッドは、列挙する要素がなくなって StopIteration
例外を送出したあとは、以降の呼び出しでもずっと例外を送出しつづけるように実装すべき。
http://www.python.jp/doc/nightly/lib/typeiter.html
staticmethod, classmethod, property
とか、 __metaclass__
とか。
…これらは v2.2 で導入された new-style class に関連している。詳細は Unifying types and classes in Python 2.2 にまとまっている。言語ヲタクが Python を習得する際には必修事項 :-)
>>> a = "short" >>> b = "short" >>> a is b True >>> a = "long text" >>> b = "long text" >>> a is b False
短い文字列は最適化でまとめられるらしい。
encodings = [ "iso-2022-jp", "utf-8", "euc-jp", "cp932", ] def detect( text ): bestScore = -1 bestEnc = None for enc in encodings: try: unicode( text, enc ) except UnicodeDecodeError, err: if err.end > bestScore: bestScore = err.end bestEnc = enc else: return { "encoding": enc, "confidence": 1.0, } return { "encoding": bestEnc, "confidence": bestScore / (bestScore + 2.0), }
Download: chardet.py
chardetという素晴らしい文字コード判定ライブラリがあるが、ちょっと使うには大げさで、速度もかなり遅い。文字コードがある程度限定されているなら、 unicode() 関数で成功するまで変換してみるという方法で文字コード判別ができる。 chardet よりずっと速かったり。
上のコードは chardet とインターフェイスを合わせてあるので、 chardet をインストールするかわりに chardet.py を置くだけで使える。ただし confidence の値は適当気味。
CPython は zip ファイルをインポートできて (zipimport) 、さらに __main__.py がアーカイブ内にあると python archive.zip したときにそれが実行される。また一方で zip ファイルはヘッダを尻に持っていて、ファイルの先頭にゴミがついていても問題なく読み込める。そこで、
$ echo "#!/usr/bin/env python" > executable $ app.zip >> executable $ ./executable
とすれば、直接実行可能なファイルが作れる。
ドキュメントを読むと、 asyncore は socket にしか使えないように思えるが、実際にはファイルオブジェクト全般に使える。基本的には、 asyncore.socket_map にファイルディスクリプタとオブジェクトを追加しておくと、適当なメソッドが呼ばれるシンプルな仕組み。以下 stdin での例:
import os import fcntl import asyncore class AsynStdin( object ): def __init__( self, map = asyncore.socket_map ): fcntl.fcntl( sys.stdin, fcntl.F_SETFL, os.O_NONBLOCK ) map[sys.stdin.fileno()] = self def readable( self ): return True def writable( self ): return False def handle_read_event( self ): pass # Do something...
from __future__ import ( division, absolute_import, print_function, unicode_literals, ) from future_builtins import *y.fujii <y-fujii at mimosa-pudica.net>