PythonTips

version date memo
0.1 2014/11/15 first

環境

OS Ubuntu 12.04
Python 2.7.3

概要

2年ぐらいPythonをやっていて溜まってきたTipsを書く

関数型言語っぽい実装

curry化

PythonのDecorator機能を用いて、curry化を実装出来る。
下記URLに実装と使い方が載っている。
PythonDecoratorLibrary - Python Wiki
実際にプログラムに組み込む際は、上記ファイルを「curry.py」などで保存して、「from curry import curried」をimport文で記述すると良い。

メソッドチェーン的な何か

此処の記事の「f_chain」を利用してメソッドチェーン的なものを利用する。
Python で Clojure っぽい関数チェーン。 - 水底で思うこと
下記の様にすると、partialが不要になり、便利さが更に加速する。

@curried
def cmap(f, x): # curry化対応map
    return map(f, x)
f_chain(a, sorted, reversed, cmap(str), '-'.join, print)

Iteration関連のゆーてぃりてぃ

Iterableかどうか

下記URL参照
A-Liaison BLOG: Pythonで変数の型をチェックする方法(Javaでいうinstanceofが使いたい)

def isiterable(x):
    return isinstance(x, basestring) or hasattr(x, '__iter__')
最終要素のフラグ付きループ

Iterableなデータ(iter, string, list, dict...)を渡すと、最終要素かどうかのフラグと要素を返すiteratorを返す。

def last_flagged(x):
    if not isiterable(x):
        raise TypeError("Invalid Type, Must be iterable: %s" % type(x))
    seq = iter(x)
    cur = next(seq)
    for y in seq:
        yield False, cur
	cur = y
    else:
        yield True, cur
# 使い方
for flag, x in last_flagged([1,2,3]):
    print flag, x
# => False, 1
#    False, 2
#    True, 3
タプルキーの分解

辞書形式でデータを登録する際に、キーをタプルで登録しておいて、後でキーの階層化を行う関数。
これを使うので注意

from collections import defaultdict

def split_keys(dic):
    if not isinstance(dic, dict):
        raise TypeError("Invalid Type, Must be dict: %s" % type(dic))
    result = dict()
    for mul_key, val in dic.items():
        target = result # ループ用
        for flag, key in last_flagged(mul_key):
            if flag:
                target[key] = val
                continue
            # keyを持っていない場合は初期化
            if not target.has_key(key):
                target[key] = {}
            target = target[key] # 次の階層へ
    return result
## 使い方
dic = {}
dic[(1,2,3)] = 10
dic[(1,2,4)] = 20
dic[(1,3,3)] = 30
dic[(1,3,4)] = 40
print split_keys(dic)
# => {1: {2: {3: 10, 4: 20}, 3: {3: 30, 4: 40}}}
# 但し
# dic[(1,2)] = 10
# などタプルのサイズが違うものが混じっているとエラーになるので注意
辞書をデフォルト値で持つdefaultdict

defaultdict(dict)としようとすると、エラーになってしまうが、どうにかしてdefaultdictの初期値をdict(又はdefaultdict)にしたいという場合。
下記参照
dictionary - Multiple levels of 'collection.defaultdict' in Python - Stack Overflow

dic = defaultdict(lambda : dict)
dic[1][2] = 2
# => {1: {2: 2}}
dic2 = defaultdict(lambda : defaultdict(int))	
dic2[1][2] += 1
# => {1: {2: 1}} # 初期値が0なので1となる

Pythonの文法関連

PEP8準拠

PEP8とか言うpythonのコーディング規約がある。
そのスタイルに則って作業を行えば、Pythoniaにとって読みやすいコードが出来るはず。
スタイルチェックとか自力でやるのは面倒だよね。
ということで、pep8というコマンドがあるらしい。

pep8解説記事
Python のソースコードを自動で PEP8 に準拠させるツール autopep8 | CUBE SUGAR STORAGE
PEP8翻訳
https://dl.dropboxusercontent.com/u/555254/pep-0008.ja.html