Python
python3

(Python3)ノ 。oO(標準ライブラリ使ってる?) : 日陰者5選

More than 1 year has passed since last update.

日陰者の関数たち

Pythonはバッテリー同梱と言われるだけあってbuilt-in関数やら標準ライブラリやらがとっても充実しています. 一方で充実しすぎて日の目を見ない関数たちも多いように思います.

これを書いたそもそもの動機はprint関数です. もっと評価されるべき.

旅行に行こう!

一度は以下に目を通しておきましょう:
Python チュートリアル
及び
標準ライブラリミニツアー
標準ライブラリミニツアー その2

print

この子自体は超有名ですが, その引数たちは日陰者かも?

Python2ではprint文だったのが, Python3からprint関数になりました. 下位互換性をぶった切る以外にどんな意味があるのかと思っていましたが, よくよく見るとすごい便利な関数に進化していました:

print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

- sep -
区切り文字を設定できます. joinと同じようなことができます:

print('a', 'b', 'c', 'd', sep='_')
# '_'.join(['a', 'b', 'c', 'd'])
>>> a_b_c_d

- end -
出力の最後につけるものを指定できます. デフォルトはもちろん\n:

print('Hello ', end=''); print('World')
>>> Hello World

- file -
これが最も感動したポイント. ファイル出力がprintで可能です:

f = open('output.txt', 'w')
print('Hello World', file=f)

ググるとwrite()だったりwriteline()を使う方法がよく紹介されていますが, これからはprintでいけます!

- flush -
バッファのフラッシュが可能です. 例えばファイル書き込みをするのはprint(..., file=f)を実行したタイミングではなく, バッファが満杯になったタイミングです. おそらくパフォーマンスのためなのですが, 実行中に書き込みファイルを覗きたい場合はとっとと出力してほしいわけです. そんなときはflushをTrueにします.

- 合わせ技 -
たとえばなんかしらの処理をするときにループの回数をコンソールに出力したいとします:

for i in range(100):
    print('rep = {0}'.format{i})
    # 以下なんかしらの処理...

>>> rep = 0
    rep = 1
    rep = 2
    rep = 3
    ...

でもこれだと出力が縦にずらずらと並んでコンソールの領域がもったいないです. 出力を上書きするようにしましょう:

for i in range(100):
    print('rep = {0}'.format{i}, '\r', end='', flush=True)
    # 以下なんかしらの処理...

\rはカーソル位置を行頭に戻すエスケープシーケンスです. これで出力が上書きされて1行に収まります. 便利ですよ.

pprint

pretty-print, 略してpprint. その名の通り出力をかわいくしてくれます. おそらくここで言う「かわいい」の定義は「コンソールの幅に合わない出力が複数行に分けて出力されている状態」のことだと思われます:

from pprint import pprint

pprint('There should be one-- and preferably only one --obvious way to do it.'.split())

>>> ['There',
    'should',
    'be',
    'one--',
    'and',
    'preferably',
    'only',
    'one',
    '--obvious',
    'way',
    'to',
    'do',
    'it.']

かわいいかどうかはわかりませんが, 便利なこともあるでしょう. なお, print関数のような万能感はありません.

shelve

数値計算結果をtxt, csvファイルなどに保存するのはよくあることですが, これをまたPythonで読み込もうとするとstring型になるのでそれをint・floatにキャスト...という手順を踏まなければなりません. shelveはPython内のオブジェクトをそのまま保存・展開できます:

import shelve

zen_string = 'There should be one-- and preferably only one --obvious way to do it.'
zen_list = zen_string.split()

# 新しいShelveオブジェクトを作る
obj = shelve.open('./test')
# dict型っぽく代入
obj['string'], obj['list'] = zen_string, zen_list
# 保存(close)
obj.close()

# 展開
obj_restore = shelve.open('./test')
print(list(obj_restore.keys()))
>>> ['string', 'list']

print(obj_restore['string'])
>>> 'There should be one-- and preferably only one --obvious way to do it.'

Pythonに住むならこれは便利なはず! ただ他の言語やツールからはアクセスできないので汎用性は?

collections.deque

listは便利なコンテナですが, 末尾以外の要素の追加・削除はとても効率が悪いです. collections.dequeは両端のappend, popが高速に実行可能です:

import numpy as np
from collections import deque
a = np.linspace(0, 1, 100000)
b = deque(a)

# IPython
%timeit -n5 a.pop(0)
>>> 5 loops, best of 3: 35.6 µs per loop

%timeit -n5 b.popleft()
>>> 5 loops, best of 3: 147 ns per loop

200倍以上はやいです. 仮にプロコンでPythonを使うなら必須かと思います.

おまけ : IPython

IPythonの便利さはいろいろなところで語られております:
IPythonの使い方

コマンドのうしろに?をつけるとヘルプを参照できたり, シェルのコマンドがそのまま使えたり, マジックコマンドとか便利です.

IPython.embed

コードを実行している途中で一旦止めてIPythonに入ります.

from IPython import embed

tmp = []
for i in range(100):
    tmp.append(i)
    if i == 50:
        # i == 50でIPythonで入る
        embed()

# IPython
In [1]: tmp
Out[1]:
[0,
 1,
 2,
 ...
 50]
# exit()とかCtrl-DとかでIPythonを出ると実行再開

たとえばおかしなエラーが起きたらその直前にembed()を挟んでオブジェクトの中身を調べてみる, みたいなことができますね. printデバッグは卒業したいけどデバッガは敷居が高い...という方に是非.

さいごに

自分がよく使うものであんまり知られてなさそうなものを挙げてみました. いいものあったら足していきます. いいものあったら教えてください.