2017-07-21 Fri 05:10
逆引きPython
INDEX
その他
.pycを作りたくない
環境変数PYTHONDONTWRITEBYTECODEを設定すると、.pyc
および.pyo
ファイルが作成されなくなる。値は何でもいいので、
export PYTHONDONTWRITEBYTECODE=1
などと書いておけばよい。
辞書(dict)のソート
キー(key)の順に取り出す
>>> score = {'Jack':300, 'Mike':200, 'Jane':100} >>> for (k, v) in sorted(score.items()): ... k, v ... ('Jack', 300) ('Jane', 100) ('Mike', 200)
値(value)の順に取り出す
>>> for (k, v) in sorted(score.items(), key=lambda x:x[1]): ... k, v ... ('Jane', 100) ('Mike', 200) ('Jack', 300)
reverse=Trueで降順になる。
>>> for (k, v) in sorted(score.items(), key=lambda x:x[1], reverse=True): ... k, v ... ('Jack', 300) ('Mike', 200) ('Jane', 100)
配列(リスト)のコピー
単に代入しただけでは参照になるので、破壊的な操作をした時に元の値も変更されてしまう。
>>> a = ['foo', 'bar'] >>> b = a >>> b[0] = 'hoge' >>> b ['hoge', 'bar'] >>> a ['hoge', 'bar']
以下のいずれかで新しいリストが作れる。
b = list(a) b = a[:]
もしくはcopyモジュールを使ってもよい。
import copy b = copy.copy(a) b = copy.deepcopy(a)
単なるリストのコピーであればシンプルに書けて高速な前述の方法を使えばよい。deep copyが必要な場合はcopy.deepcopyを使う。
ベンチマークを取るとスライスが最も速いが、listを作り直す方が意味は伝わりやすい。速度差も小さく、dictにも応用が効く。
文字列からクラス名を決める
クラス名を動的に決定する場合はglobals()からクラスを取得する。
>>> class Hoge(object): ... pass ... >>> globals()['Hoge']() <__main__.Hoge object at 0x10d62e390>
正直ちょっと無理矢理感があるが、実際のアプリケーションではこのような操作の対象は特定のモジュールにまとまっているはずで、その場合はもっとスマートに書ける。
myapp.commandsモジュールから動的にクラスを決定してインスタンスを得る。
import myapp.commands obj = getattr(myapp.commands, 'Hoge')()
スクリプトを終了する
exit()ではなくsys.exit()を使う。
import sys sys.exit(exit_code)
exit()はインタラクティブを終了するためのショートカット(^D相当)であって、実行の停止ではない。
メールを送信する
import smtplib from email.MIMEText import MIMEText from email.Header import Header from email.Utils import formatdate def send(from_addr, to_addr, subject, body=None, encoding='utf-8'): if isinstance(body, unicode): body = body.encode(encoding) msg = MIMEText(body, 'plain', encoding) msg['Subject'] = Header(subject, encoding) msg['From'] = from_addr msg['To'] = to_addr msg['Date'] = formatdate() s = smtplib.SMTP('localhost:25') s.sendmail(msg['From'], msg['To'].split(','), msg.as_string()) s.close()
decimal.Decimalを指定の桁で丸める
Pythonで浮動小数点演算をおこなう場合は、誤差を避けるためにfloatではなくdecimalを用いる。
指定の桁で数値を丸めるには、quantizeメソッドを使う。
>>> import decimal >>> decimal.Decimal('1.05').quantize(decimal.Decimal('0.0'), rounding=decimal.ROUND_HALF_UP) Decimal('1.1')
roundingの種別はdecimal.Contextに詳しいが、基本はこの3つ。
- 切り捨て : ROUND_DOWN
- 切り上げ : ROUND_UP
- 四捨五入 : ROUND_HALF_UP
decimal.Decimalといちいち書くのは面倒なので、今のところチームのルールとして以下を設定している。
- from decimal import Decimalで直接クラスをimportしてよい
- テストコードのみfrom decimal import Decimal as Dで省略してよい
cached_propertyの励行
werkzeug.utilsにあるcached_propertyの使用を推奨する。
社内でコードを書く場合は、ポートしたものがkauli.utilsにいるので以下のようにimportする。
from kauli.utils import cached_property
通常のpropertyと比較して、キャッシュによるパフォーマンスの向上以外にも、
class Hoge(object): @cached_property def foo(self): return 'FOO' hoge = Hoge() hoge.foo = 'BAR'
このように外部から値を注入できるのでテストを書く際にも便利である。
cached_propertyはキャッシュ可能なプロパティというよりも、遅延評価されるインスタンス変数と表現した方が適切なようにも思われる。通常のpropertyと適宜使い分けたい。