[Python入門]Pythonコーディングスタイルガイド:Python入門
Pythonのコードを記述する際の基本的なコーディングスタイルを定めたPEP 8について紹介しよう。長かった連載もようやく完結!
読みやすくて、可読性が高く、一貫性のあるPythonコードを書くための基本的なコーディングスタイルガイドであるPEP 8を紹介する。
PEP 8とは
PEP(Python Enhancement Proposal)とは、Pythonの新機能に関する仕様やその背景を、Pythonコミュニティーに対して提供する文書のことだ。これまでに数多くのPEPが発行されているが、その中でPEP 8は「Style Guide for Python Code」と銘打ち、Pythonコードを記述する際の決めごとを定めたものとなっている。
Pythonは誰が書いても同じようなコードとなりやすいように作られた言語だが、そうはいってもコードの書き方そのものが言語仕様上でガチガチに定められているわけではない。例えば、if文を例に取れば、同じコードでも次のような書き方ができる。
#書き方その1
if x == 0: print('x == 0')
# 書き方その2
if x == 0:
print('x == 0')
# 書き方 その3
if x == 0:
print ( 'x == 0' )
if節の本体を改行なしで書くこともできるし、空白文字はある程度自由にコード中に含めることもできる。どんな書き方をするかは、プログラマーに一任されている。だが、これでは誰の目にも見やすくて一貫性のあるコードを、誰もが書けるかは難しい。そこで、PEP 8は、プログラムを書く上での基本的な作法を定め、それに従うことで、誰の目にも同じように見え、その意味を把握しやすいコードを誰もが書けるようにしている。
その一方で、PEP 8の冒頭では「頑迷にスタイルガイドにこだわりすぎるのもよくない」といった意味の文章が書かれてもいる。そこでは、モジュール>プロジェクト>Pythonの世界といった順序で一貫性したコードとなっていることが重要であるとされている。そのため、PEP 8とは異なるスタイルで書かれているコードを利用する際に、そのモジュールと自分の書くコードとはスタイルが異なる可能性もある。そのときに、一貫性にこだわりすぎて、自分のコードを既存のモジュールに合わせる必要があるだろうか。あるいは、複数人が関わるプロジェクトでどのようなスタイルでコードを書くべきだろうか。こうしたときには、あえてPEP 8で定めるスタイルから外れることも考えよう。
PEP 8の全てをここで説明するのは無理なので、以下では基本的な部分について取り上げていこう。
コードレイアウト
Pythonはインデント付けによって、そのブロックを明示するタイプの言語である。そこでPEP 8では次のスタイルが推奨されている。
- インデントを付けるにはタブ文字ではなく、半角空白文字を使用する
- タブ文字を使うのは、既にあるコードでタブ文字をインデントに使っているものに合わせるときだけとする
- 1つのインデントごとに4文字の半角空白文字を使用する
- 1行の長さは最大で79文字まで
- docstringやコメント行については、1行は72文字までとする
- 行を継続する場合には、非明示的な行継続を明示的な行継続よりも優先して使用する
- 2項演算の途中で改行をするときには、その演算子の前で改行を入れた方が読みやすいコードになる(「(a + b)」の「+」の前で行頭に演算子が現れるようにした方がよい)
- モジュールのトップレベルの関数定義やクラス定義は、2つの空行で区切る
- クラス定義内のメソッド定義は、1つの空行で区切る
- 関数やメソッドの定義内では、ひとまとまりのコードを区切るのに追加で改行を含める
- import文では一度に一つのモジュールだけをインポートする(「import module1, module2」のような書き方は推奨されない)
- あるモジュールから複数の要素をインポートするときには、インポート対象をカンマで区切って並べる(「from module1 import some, other」と書くことが推奨される)
- 「from module import *」形式のインポートは避けるべき
このうち、非明示的な行継続を使用して、1行を複数行に分けて書いているときには、インデントをどうすべきが問題になることがある。PEP 8では次の書き方を推奨している。
# 1行目に引数を書き、その位置に2行目以降を合わせる
result = some_func(long_var_name1,
long_var_name2,
long_var_name3)
# 1行目には引数を置かず、追加のインデントを含める
def some_func(
long_param_name1, # 関数の本体と区別が付くようにインデントを2段階付ける
long_param_name2,
long_param_name3):
# function body # ここからが関数定義の本体
pass
result = some_func(
long_var_name1,
long_var_name2,
long_var_name3)
# よくない例
result = some_func(long_var_name1,
long_var_name2, long_var_name3) # ×:1行目の引数位置にインデントは合わせる
空白文字の使い方
空白文字の使い方を以下の表にまとめる(抜粋)。
使い方 | よい例 | 悪い例 |
---|---|---|
開きかっこの直後、閉じかっこの直前には 入れない |
func(arg1, arg2) ary[0] tpl = (0,) |
func( arg1, arg2 ) ary[ 0 ] tpl = (0, ) |
カンマ/セミコロン/コロンの直後に入れ、 直前には入れない |
print(x, y) if x == 0: print('value:', x) |
print(x , y) if x == 0 : print('value:' , 'bar') |
開きかっこの直前には入れない | func('foo') mydict['foo'] |
func ('foo') mydict ['foo'] |
空白文字で代入演算子の位置をそろえない | foo = 'foo' bar = 'bar' hoge = 'hoge' |
foo = 'foo' bar = 'bar' hoge = 'hoge' |
二項演算子や累算代入演算子などの前後には 空白文字を1つ入れる |
x = 1 a += 1 |
x=1 a+=1 |
優先順位が異なる演算子が1つの式中に現れる ときには、優先順位が高いものの前後には空白 文字を含めない |
a = x*x + y*y | a = x * x + y * y |
関数定義でデフォルト引数値を指定するとき には「=」の前後に空白文字を入れない |
def func(x=0, y=0): | def func(x = 0, y = 0): |
関数呼び出しでキーワード引数に値を指定する ときには「=」の前後に空白文字を入れない |
func(x=1, y=1) | func(x = 1, y = 1) |
複合文を1行にまとめない | 以下を参照 | 以下を参照 |
空白文字の使い方 |
最後の「複合文を1行にまとめない」というのは、if文やdef文のように、複数の文で構成される文は1行で書くことも可能だが、それはしないようにしようというものだ。以下は、通常の書き方でif文を書いたものだ。
x = input('input number: ')
if x.isdecimal():
x = int(x)
このif文は、コロンに続けて空白文字を含め次のようにも書ける。
x = input('input number: ')
if x.isdecimal(): x = int(x)
しかし、PEP 8では基本的にはこの書き方は推奨していない。ただ、上のように本体がシンプルなときには使ってもよい。ただし、節が複数あったり、本体が複数行で構成されたりするときには、使用しないことが強く推奨されている。以下にダメな例を示す。
# ×:if節とelse節がある
if x == 0: print('zero')
else: print('other')
# ×:if節の本体が複数行あり、セミコロン「;」で連結している
if x == 0: print('zero'); some_func('some_value')
# ×:節が複数ある
try: some_func('some_value')
except: print('error')
else: print('not error')
finally: print('finally')
コメント
コメントについては以下が推奨されている。
- コードの内容と相反するコメントは最悪なので、コードを修正したら、コメントもそれに合わせて更新すること
- 非英語圏のプログラマーであっても、そのコードを使うのが自分の母語を使う人たちと確信できるとき以外は、英語でコメントを書いてほしい
- コメントはちゃんとしたセンテンス(文)とすべき
- ブロックコメントはちゃんとしたセンテンスで構成された段落を1つ以上含むものとする
- センテンスは大文字で始まり、ピリオドで終わり、次のセンテンスとの間には半角空白文字を2つ含める
- ブロックコメントはそれが対象とするブロックのインデントに合わせる
- ブロックコメントの各行は「#」で始め、その後に半角空白文字を1つ含める
- ブロックコメントが複数の段落で構成されるときには、それらは「#」だけを含んだ行で区切る
- インラインコメントは、あまり使わないようにする
- インラインコメントとコードの間には最低でも2つの半角空白文字を入れ、その後に「#」に続けてコメントを記述する
- コードでしていることを冗長に書くのではなく、なぜそうしているのかを(その理由が分かりづらいときに)説明するのに使用する
命名規約
以下に変数、関数、クラス、メソッド、モジュールなどの命名時に推奨されている事項をまとめる。
対象 | 推奨事項 | 例 |
---|---|---|
定数名 | ・全て大文字で単語間をアンダースコアでつなぐ | CONSTANT MAX_CHAR |
関数名/変数名 | ・英小文字を使用し、可読性を高めるときには 単語間をアンダースコアでつなぐ ・変数の命名時には、判別が難しいことから、 単独の「l」(小文字のエル)、 「O」(大文字のオー)、 「I」(大文字のアイ)は使わない ・ASCIIの範囲に含まれる文字だけを使用する |
a foo pos_x |
クラス名 | ・各単語の先頭だけを大文字化したものを、 アンダースコアを使わずにつなぐ |
Coordinate MyClass |
関数/メソッドの パラメーター名 |
・インスタンスメソッドの第1パラメーターの 名前は常に「self」とする ・クラスメソッドの第1パラメーターの名前は 常に「cls」とする ・パラメーター名が、予約語と重なるときには、 末尾にアンダースコアを付加する(例:class_) |
− |
メソッド名/ インスタンス変数名 |
・基本的には関数名/変数名と同様 ・外部に公開しないものは先頭にアンダースコアを 1つ付加する ・さらに強力にアンダースコアを2つ先頭に付加すると、 メソッド名/インスタンス変数名がマングリングされる |
MyClassの__foo属性 はMyClass.__fooへと マングリングされ、foo という名前ではアクセス できなくなる |
モジュール名/ パッケージ名 |
・モジュールとパッケージは全て小文字で 短い名前とする ・モジュールについては可読性が高くなるのであれば アンダースコアを使ってもよいが、パッケージでは アンダースコアを使用しない |
my_module(モジュール) mypkg(パッケージ) |
変数、関数、クラス、メソッド、モジュール、パッケージの命名規約 |
この他にも、命名規約はいろいろとあるが、それらについてはPEP 8を参照されたい。
まとめ
今回はPythonのコードを書く際に準拠すべき、基本的なスタイルを示しているPEP 8を紹介した。PEP 8はPythonのコードを書く上で基本となるスタイルガイドだが、実際にコードを書くときにはまた別のスタイルガイドに準拠したり、チーム内でより制約の強いスタイルガイドに従ったりする必要もあるだろう。ただし、多くの場合、開発環境やエディタなどが、それらのスタイルに準拠したコードを容易に書けるように、何らかの形でサポートしていることもある。全てを覚えるのではなく、そうしたツールやサポートを便利に活用するのがよいだろう。
本連載はひとまずここで筆をおくが、紹介し切れていないことはまだまだたくさんある。それらについては上級編となる連載で取り上げていく予定だ。本連載が多くのPython入門者の役に立てば幸いだ。
今回のまとめ
- PEP 8は、読みやすくて、可読性が高く、一貫性のあるPythonコードを書くための基本的なコーディングスタイルガイドである
- PEP 8では、コードレイアウト、空白文字の使い方、コメントの書き方、変数などの命名規約などが定められている
Copyright© Digital Advantage Corp. All Rights Reserved.