はじめに
Python 3.8 対応の「Effective Python」第2版が出ていたので買って読みました。
Pythonの初学者~中級者向けの内容で、Python上級者を目指す場合は必須の書籍です。
ネットで検索すれば分かりますが、ほとんどのPythonエンジニアが1度は読んだことのある書籍です。
技術書・翻訳書なので少し値段は張りますが、読んで損のない究極の一冊です。
今回は、Python初・中級者を対象に、Effective Python から項目をいくつかピックアップして紹介します。
内容が分かりにくい方は、ぜひ購入して読んでみてください。(販促)
こんな方におすすめ
- プログラミング言語「Python」の知識を深めたいけど、何をすればよいか分からない
- Python中級者から上級者への橋渡し的な書籍を探している
PEP8スタイルガイドに従ってコーディングすべし
第1章「Pithonic思考」で記載されているコーディングスタイルについてです。
どの言語にもリファレンスとなるスタイルガイドがありますが、
Python言語では PEP8(Python Enhancement Proposal No.8)が最もよく知られています。
※PEP8(https://pep8-ja.readthedocs.io/ja/latest/)
なぜコーディングスタイルを定義するのかというと、理由は大きく2つあります。
- 一貫したスタイルで記述して可読性をあげることで、誤読や不具合混入を防げる
- さらに、保守性も向上し、変更や不具合修正もしやすくなる
PEP 8の全てをここで説明するのは無理なので、以下で代表的な部分を紹介します。
空白・インデント
Python言語では、「空白」が構文以上の意味を持つため特に気をつける必要があります。
- インデントは、タブではなく空白を使う
- 構文上意味を持つインデントには、4個の空白を使う
- クラス定義では、空白行を空けてメソッドを定義する
- 変数へ代入する前後では、空白を1つ使う
命名規則(名前付け)
PEP8では、種類の異なる定義ごとに異なるスタイルを用いることを推奨しています。
- 関数名、変数名、属性名は、lowercase_underscore のように小文字でアンダースコアを挟む
- プロテクテッド属性は、_leading_underscore のように先頭にアンダースコアを付ける
- プライベート属性は、__double_underscore のように先頭にアンダースコアを2つ付ける
- クラス名と例外は、CapitalizedWord のように単語先頭を大文字にする
式と文
Pythonの構文に従って処理を記述する場合のスタイルです。
- 式の否定は(if not a is b)ではなく、内側の項の否定(if a is not b)を使う
- if文、for ループ、while ループ、except 複合文は1行で書かずに複数行で書く
- 式が1行に収まらない場合は、括弧を使って複数行にする
PEP8スタイルガイドまとめ
- Pythonのコードを書くときは常に PEP 8 スタイルガイドに従う
- 大きなOSSなどのコードを参考にスタイルを共有することで、チームでの作業がはかどる
- 一貫したスタイルを用いることで、自分のコードを後で修正しやすくなる
ループには range ではなく enumerate を使うべし
これは私も最初耳が痛かったです。
ここで紹介している内容を見て、「あ・・・私も・・・」という方も多いと思いますよ。
range はどう使う?
組込み関数 range は、for 文のループ処理を行うときによく使います。
例えば、以下のように1から9の数字を使って九九表を出力する場合などです。
1 2 3 4 5 6 7 |
for i in range(1, 10): for j in range(1, 10): ans = str(i * j) ans = ans.rjust(4) print(ans, end=" ") print("") |
1 2 3 4 5 6 7 8 9 10 |
1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81 |
enumerate はどう使う?
例えば、以下のように色のリストを出力するプログラムがあったとします。
1 2 3 4 |
color_list = ['red', 'blue', 'yellow', 'white', 'black'] for color in color_list: print(color) |
color_list.pyの実行結果
red
blue
yellow
white
black
リストの処理で、リストの要素のインデックスが必要な場合ってよくありますよね。
例えば、ランキングを出力したり、解析用に情報を追加したり。
まず考えられるのは、先ほどの range を使う方法です。
1 2 3 4 5 |
color_list = ['red', 'blue', 'yellow', 'white', 'black'] for i in range(len(color_list)): color = color_list[i] print(f'{i + 1}: {color}') |
color_list_rank.pyの実行結果
1: red
2: blue
3: yellow
4: white
5: black
Pythonには、このような状況に対する組込み関数 enumerate が用意されています。
enumerate は、イテレータをラップします。ランキングの例を書き換えると、以下のようになります。
1 2 3 4 |
color_list = ['red', 'blue', 'yellow', 'white', 'black'] for i, color in enumerate(color_list, 1): print(f'{i}: {color}') |
enumerateのまとめ
- range のループでインデックスを処理するよりも enumerate を使う方がよい
- enumerate の第2引数で、カウンタを開始する数を指定できる
getやsetのメソッドは使わず属性をそのまま使うべし
他の言語を習得後に Python を触り始めた方は、クラスの中で getter(ゲッター)や setter(セッター)のメソッドを実装します。他の言語では、クラスのメンバー変数にアクセスする際のマナーになっていたりするためです。
1 2 3 4 5 6 7 8 9 10 |
class OldImplementation: def __init__(self, val): self._value = val def get_val(self): return self._value def set_val(self, val): self._value = val |
Pythonでは、@property デコレータや、それに対応する setter 属性をマイグレートできます。
そのため、上記のようにしなくても、属性が設定されたときに特別な振る舞いを後から追加できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class BoundedImplementation(OldImplementation): def __init__(self, val): supper().__init__(val) @property def value(self): return self._value @value.setter def value(self, val): if val <= 0: raise ValueError(f'val must be > 0') self._value = val |
上記のように、セットする値の検証処理をかんたんに追加することが可能です。
@propertyデコレータのまとめ
- パブリック属性を使ってクラスのインターフェイスを定義し、set や get は定義しない
- 必要になれば、@property を使って属性アクセスされたときの振る舞いを記述
try / except / else / finally の各ブロックを活用せよ
Python で例外(実行中に検出されたエラー)をキャッチして処理するには try や except を使います。
例外が発生しても途中で終了させずに処理を継続できます。
さらに、else や finally を使うことで、終了時の処理を設定することが可能です。
1 2 3 4 5 6 7 8 9 10 |
with open(filename, 'wb') as f: try: f.write(b'\xf1\xf2\xf3\xf4\xf5') # 不正な UTF-8 return True except UnicodeDecodeError as e: print('catch error') # 例外のキャッチ return False finally: f.close() # 常に実行される |
ここでは個々のブロックを詳しく説明しませんが、それぞれのブロックが果たす独特の目的、
役立つ組み合わせ等が事細かに紹介されています。
ポイントだけ書いておきます。
ポイント
- try と finally の複合文では、try で例外発生有無に関わらず後始末処理を記述できる
- else ブロックは、try が成功した後で、finally の前に追加書を行う
まとめ
いかがでしたでしょうか。
私が購入した Effective Python 第2版では、全90項目が記載されています。
そのうちの4項目を本記事で紹介いたしました。
もう一度、言います。
Effective Python は、どのレベルのプログラマにも役に立つ究極の一冊です。
以下、再び販促(笑)