Pythonをマスターするなら身につけておきたい10項目

原題 "I Thought I Was Mastering Python Until I Discovered These Tricks"
原文は下記リンク先へ:

これらのトリックに気がつくまでは、Pythonはマスターしたものと思っていたよ!といったところだろうか。Pythonを習得するにあたってぜひ知っておきたいTIPSとかテクニックが10項目紹介されているので、以下にざっくりと:

1. 可読性(読みやすさ)が大事

Pythonに限らず、プログラムは好き勝手な体裁で書くのではなく、ある程度慣習化されたルール(programming conventions)に従って記述するべきである。他人があなたのコードをすぐ理解できるくらい読みやすいコードにしておけば、再利用性も向上する。
Style Guide for Python Codeなどを参照して、どのようなコードの書き方が読みやすいか確認しよう。

2. 不要な条件式は使わない

if & elif & elif & ... & elseといった複雑な条件分岐は、コードが長くなるし解読が難しくなる。場合によってはifブロックを使わなくても記述可能であるので、できるだけifやelseの存在は忘れてみよう。
例えば、与えられた年がうるう年であるか否かは、ifやelseを一切使わずに以下の1行の関数で判別可能である:

def is_leap(year):
    return year % 4 == 0 and (year % 400 == 0 or year % 100 != 0)

3. スペースや改行の適切な使用

タブとスペースを混在させないとか、関数の間には空行を入れるとか、代入・比較演算子の前後にはスペースを・・・などなど。
可読性とも関わるところであり、スペースや改行も統一した記述ルールで適切に入力しよう。

4. Docstringとコメント

Docstringは、そのコードをどうやって使うのか?がわかるように記述する。その関数の目的や、与えるべき引数の内容、返り値の内容など。Docstring Conventionsも参考にしよう。
コメントは、そのコードがどうして/どのようにして動くのか?がわかるように記述する。後々そのコードをメンテナンスする際に役立つような、バグ情報や、修正するべき内容、不明点など。
Docstringもコメントも、常に最新情報にしておくことが重要である。コード内容を修正したら、Docstringやコメントの内容も見直そう。

5. 変数と代入

タプルに関連する代入の仕組み(パック/アンパック)をマスターすると、for文などで便利に使うことができる。
以下は一例:

>>> user =['Jan', 'Gomez', '+1-888-222-1546']
>>> people = [user, ['German', 'GBT', 'unlisted']]
>>> for (name, title, phone) in people:
...      print (name, phone)
...
Jan +1-888-222-1546
German unlisted

6. リストの接続・結合

文字列リストの内容をすべてつなげて、ひとつの大きな文字列としたい場合に、以下の方法は非効率である:

color = ['red', 'blue', 'green', 'yellow']
result = ''
for s in colors:
    result += s

代わりにjoin()メソッドを使うと高速に処理できる:

result = ''.join(color)

リストの要素数が少なければ両者の処理速度は大差ないが、数百あるいは数千といった数になると、劇的な差が生じる。

7. TrueかFalseかの判別

条件式がTrueかFalseか、あるいはあるリストが空であるか否か、を判別する際にはより効率の良い書き方をしよう:

# Do this :     # And not this :
if x:             if x == True:
    pass              pass

# Do this :     # And not this :
if items:         if len(items) != 0:
    pass              pass

# and especially not that :
       if items != []:
           pass

8. enumerate()関数

enumerate()関数は、与えたリストに対して、(インデックス番号, リスト要素)というタプルを返すものである。ただしenumerate()関数は、for文等で利用できるようにリクエストベースで都度タプルを生成する(いわゆるイテレータ)ため、使い方は以下のようになる:

items = ['zero', 'one', 'two', 'three']
for (index, item) in enumerate(items):
    print (index, item)

enumarate()を使用した上記のコードは、下記の2例に比べると記述が短く簡潔である:

# compared to :               # And :
index = 0                     for i in range(len(items)):
for item in items:                print (i, items[i])
    print (index, item)
    index += 1

9. リスト内包表記

forとifを使って、通常なら以下のように書きがちなところは、

new_list = []
for item in a_list:
    if condition(item):
        new_list.append(fn(item))

リスト内包表記を使うと以下の1行で済む:

new_list = [fn(item) for item in a_list if condition(item)]

10. ジェネレータ

1から100までの整数の二乗の合計を求めたい場合、リスト内包表記を利用しても良いが、ジェネレータとしてほぼ同じ記述で表現することができる:

# With a list comprehension :
total = sum([num * num for num in range(1, 101)])

# With a generator expression :
total = sum(num * num for num in xrange(1, 101))

表記上の違いはブラケット"[ ]"の有無だけであるが、両者が決定的に異なる点は処理速度とメモリ使用量である。
リスト内包表記の場合は、一度リストを生成してメモリに保持するため、それだけ処理時間とメモリが必要になる。
対して、ジェネレータ表現の場合は、リストは生成せずに一回の処理で最終的な計算結果(上記コードでいうとsum()関数の結果)までを処理するため、処理速度とメモリの観点で有利となる。
最終的な計算結果のみが必要である場合は、ジェネレータ表現を使うと良いだろう。

所感

enumerate()関数など(個人的には)ちょっと使用場面が限られるなぁという内容もあるけど(どうしても10項目にしたかったのかな。笑)、初心者の力技コードから脱却するのに役立つ内容が多く挙がっていると思う。
私も初心者なので記事内容を参考に少しずつステップアップしたい。まずはStyle Guideを一読しましょうかね。
リスト内包表記やジェネレータを使いこなしてるとかっこいいよね。

なおジェネレータのサンプルコードにてxrange()が使われているが、Python3では廃止されている模様。なのでPython3ではrange()を使おう。

全文拙訳

気が向いたらそのうち。