いろんなものはつながっている

Effective Pythonを読んでみた(1): 1章 Python流思考(Pythonic Thinking)

Effective Python: 59 Specific Ways to Write Better Python を読んだときのメモ。

1.使っている Pythonのバージョンを知っておく(Know Which Version of Python You’re Using)

・バージョンは以下のコードで表示できる。
>>> import sys
>>> print (sys.version)
3.6.3 |Anaconda, Inc.| (default, Oct 15 2017, 07:29:16) [MSC v.1900 32 bit (Intel)]
>>> print (sys.version_info)
sys.version_info(major=3, minor=6, micro=3, releaselevel=’final’, serial=0)

2.PEP 8スタイルガイドに従う(Follow the PEP 8 Style Guide)

・命名則
 変数名は fft_point というように小文字とアンダースコアで表現する
 protected instancedは _leading_underscore
 private instanceは __doubel_leading_underscore
 クラスや例外は ALL_CAPS で。
 クラスのインスタンスメソッドの最初の引数はselfで
 クラスメソッドの最初の引数はclsで

・表現
 if not a is b ではなく if a is not b と書く
 emptyを if len(price_list) というように長さでチェックしない。if not price_list とチェックする
 importは、明示的に from bar import foo と書く。
 

3.bytes, str, unicodeの違いを知っておく(Know the Differences Between bytes, str, and unicode)

Python 3では、文字列の表現はbytesとstrの2種類がある。bytesは8bitの値が、strはUnicode値が設定されている。

Python 2の文字列表現は、strとunicodeの2種類がある。strは8bitの値が、unicodeにはUnicode値が設定されている。

Unicodeをバイナリに変換するには encode 、その逆は decode する必要がある。

pythonのプログラム中ではunicodeで扱うことを推奨している。

コード内で、バイナリまたはUnicodeを想定しているかをしっかり意識すること。

入力文字列がバイナリであれ、Unicodeであれ、想定したタイプの文字列へ変換する関数を用意すると便利。
#Unicodeに変換する(Python 3)
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode(‘utf-8′)
else:
value = bytes_or_str
return value

ファイルの入出力、Python 3ではUnicodeで扱われる。バイナリで扱いたい場合は、明示的に’wb’でファイルをオープンする。
with open(‘c:\random.bin’, ‘wb’) as f:
f.write(os.urandom(20))

4.複雑な式の代わりにヘルパー関数を書く(Write Helper Functions Instead of Complex Expressions)

or や キャスト を安易に使わず、意図がわかるような名前をつけたヘルパー関数を用意したほうがいよい。

keyが見つからなかった場合、0 をかえすというような場合

values.get(key, [”])[0] or 0

と書かずに以下のようにif文を用いて書く。

本文にのっていた例:
def get_first_int(values, key, default=0):
found = values.get(key, [”])
if found[0]:
value = int(found[0])
else:
value = default
return value

5.シーケンスをどのようにスライスするか知っておく(Know How to Slice Sequences)

b=a[0:10]とかb=a[5:len(a)]というような冗長な書き方はしない。

6.1つのスライスでは、 start, end, strideを使わない(Avoid Using start, end, and stride in a Single Slice)

b=[2:-1:2] というように、いっぺんに指定しない。

b=[::2]
c=b[1:-1]
といった書き方をする。

7.mapやfilterの代わりにリスト内包表記を使う(Use List Comprehensions Instead of map and filter)

mapやfilterよりリストの内包表現のが読みやすいから簡単な処理の場合は、リストの内包表現を使おうね。
a=[1, 2, 3, 4, 5]
b = [x**2 for x in a]
のほうが
b = [lambda x: x**2 , a)
よりわかりやすいよね。

8.リスト内包表記には、 3つ以上の式を避ける(Use List Comprehensions Instead of map and filter)

リストの内包表現のが読みやすいからといってあまり複雑な処理はしないようにね。
素直に複数のfor文とかにしてね。

9.大きな内包表記にはジェネレータ式を考える(Use List Comprehensions Instead of map and filter)

内包表記は一度の処理をしてメモリに展開してしまうから、扱うデータのサイズが大きいとOut of Memoryになる危険性がある。
だから、generator式を使おうね。

例えば、ファイルを開いて各行の長さを求める場合、内包表記ではファイルを一気に読み込み各行の長さを求めて
each_line_length = [len(x) for x in open(‘c:\aaa.txt’)]

ジェネレータ式を用いると、以下のような書き方になる
it = (len(x) for x in open(‘c:\aaa.txt’))

各行の行数を求めるには next(it) とする
例えば、print(next(it)) と。

こうすれば、一度にファイルを読み込み各行の長さを求めることにならない。
ただし、next(it) のたびにファイルオープンが走るのでは。

また、ジェネレータ式は入力しても使える。例えば、
root = ((x, x**0.5) for x in it)
とすると、
next(root)を実行するごとに、各行の文字数が取得され、そのルートが計算される。

ジェネレータ式で返されるイテレータはstatefulである点に注意することとあるが、どういうことかな。

10.rangeよりは enumerateにする(Use List Comprehensions Instead of map and filter)

for i, item in enumerate(item_list, 1):
print(‘%d: %s’ % (i, item)
って書いたほうが楽で見やすいですよってこと。

11.イテレータを並列に処理するには zipを使う(Use List Comprehensions Instead of map and filter)

zipって便利なものがあるよってことか。

for i in len(name_list):
name = name_list[i]
type = type_list[i]

なんて書かなくても

for name, type in zip(name_list, type_list):

と書けますよということか。

12.forとwhileループの後の elseブロックは使うのを避ける(Use List Comprehensions Instead of map and filter)

そもそも用途、使い方がよくわからないからいいか。

13.try/except/else/finallyの各ブロックを活用する(Use List Comprehensions Instead of map and filter)

elseブロックは、tryして成功した場合の処理を書くところ。また、try成功後、finallyの処理の前に実行する処理ともいえる。

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

スポンサード リンク

カテゴリー

スポンサード リンク