今回はコーディング規約について学びます。今までの回では特に断らずに変数やクラスに名前を付けたりしていました。また、インデントなども特に深い説明はしていません。
自分ひとりでコードを書くのであれば、自分にとってわかりやすいものをつけてかまいません。初心者のうちは細かい制約にこだわるよりも、コードを書くことのほうが上達への近道だからです。ただ、自分が書いたプログラムをほかの人が読んだり、自分もほかの人のコードを読む機会が増えたりするのであれば、少し事情が変わってきます。
多くの人がひとつのプログラムを作る場合、個人個人が自分の好き勝手にコードを書くと、スタイルがバラバラになってしまい、コードの品質を維持できなくなってしまいます。そのため、「このようにしましょう」というルールを設けて、それにしたがってコードを書きます。そのルールが「コーディング規約」と呼ばれているものです。
コーディング規約はルールですので、さまざまなものがあります。チーム単位のものもあれば、組織単位で決まっている場合もあるでしょう。ここでは「PEP8」と呼ばれているPythonの最も標準的なコード規約について取り扱います。必ずこれを採用する必要はないのですが、多くの人がPEP8の規約を意識してコードを書いているので、この規約を守ることで、ほかの人はあなたのコードを読みやすくなりますし、あなたもほかの人のコードを読みやすくなります。
PEP8について
PEP8が決めるコーディング規約は多岐にわたります。そのため、いきなり隅から隅まですべてを暗記しようとするのではなく、重要なことをかいつまんで理解し、徐々に深掘りしていくという形で覚えていくほうがよいでしょう。
本記事ではPEP8の本家で書かれていることをすべて網羅するということはせず、いくつかのトピックを選んで紹介していきたいと思います。また、PEP8に存在しない一般的なプログラミングで使われる規約についても扱います。ある程度、PEP8についてわかったら、以下のページでより詳細を学ぶことも容易になるのではないでしょうか。
なお、多くのプロジェクトはすでにコード規約を持っていることが想定されます。その規約はPEP8に沿ったものであることが望ましいですが、異なる場合はプロジェクトの規約が当然ながら優先されます。
やらないこと
必要以上にコードを「グローバル」にしない。今までグローバル変数を利用してきましたが、グローバルだとどこからでもアクセスが容易なため、意図せず中身が変わっている場合があります。参照したいだけであれば「定数」を使い、特定の一連の処理でしか利用しないのであればクラス変数とすることで、インスタンスを共有している 複数の処理のあいだでしか値を変更できないようにするべきです。ただ、グローバルといっても「定数」や「関数」は基本的に別のものになることはないので、積極的に活用すべきです。その場合はわかりやすいユーティリティ用のモジュールなどとするとよいかもしれません。
命名規約
コードを書くうえで名前をつける機会は多いです。一番小さいものですと関数やメソッド内のローカル変数、大きなレベルだとモジュール名あたりになります。命名をするうえでまず覚えておくべきことは、
- 名前は「役割」を示す
- 関数とメソッド名は「動詞」を使う
- それ以外の命名は「名詞」を使う
ということが挙げられます。これはPythonにかぎらない一般的な規則です。
たとえば変数a、b、cはサンプルコード以外では使用すべきでない名前です。aに何が入っているかさっぱりわかりませんよね。このような変数名を利用していると、その変数に値を代入している箇所を確認しないと中身が想像できません。一方、変数名average_xxxは、xxxの平均値だということがすぐにわかります。最悪なのはaverage_xxxに平均ではなく合計値が入っているような場合で、これは文法的にはバグではないものの、読んだ人を誤解させるのでバグ相当の誤りとなります。
キャメルケース(CamelCase)方式
キャメルケースは名前をつける際に単語と単語の節目を大文字にするという命名規則です。キャメルケースという呼び方はその見た目からきており、大文字がちょうどラクダ(Camel)のコブのように見えるからです。
CamelCase方式。大文字がらラクダのコブのように見える (By Silver Spoon Sokpop) |
Pythonではこの方式をクラス名に利用しており、最初の1文字目と単語の区切りが大文字になります。それ以外はすべて小文字です。Javaなどでは変数名にもキャメルケース(最初の1文字は小文字)を利用することがあるので、混同しないように注意してください。
スネークケース(snake_case) 方式
キャメルケースとともによく使われる方式がスネークケース(snake_case)方式です。単語と単語の間をアンダースコア _ でつなぐという方式で、このアンダースコアが蛇のように見えるのでスネークケースと呼ばれているようです。
大事なことは呼び方というよりもスネークケースがキャメルケースよりもパッと見で単語と単語の境界がわかりやすいということです。たとえば、以下を見比べてみてください。
- ThisIsAPen
- this_is_a_pen
多くの人にとっては、キャメルケースよりもスネークケースのほうがパッと見でわかりやすいかと思います。そのためPythonではスネークケースが多く使われ、先ほどのクラス以外、つまり変数や関数、モジュール名などもスネークケースを使います。ただ、モジュール名はスネークケースすら使わない場合が多く、一単語にするか小文字でくっつけてしまうことも多いようです。
その他
そのほかは個別ルールとなります。定数は大文字とアンダースコアを使った命名をします。たとえば、"THE_VALUE = 10"といった具合になります。この書き方はスネークケースとはあまり呼ばれず、定数独特の書き方で、手続き型やオブジェクト指向型ではよく使われます。
そのほかにはメソッドの第一引数をselfにしたり、クラスメソッドの第一引数をclsにすることもルールです。以前お伝えしましたが、これらは異なる名前であっても文法的に誤りはないのですが、PEP8も含めて皆がこうしましょうと決めたルールなので、守ってください。
ほかには他の言語などで使われている予約語や特別な意味を持つ単語もあまりオススメできません。たとえばprivateなどを変数にくっつけると、本来はprivate(外から見えない)でないのにprivateという名前がついていると勘違いされかねません。
あとは使いたい単語がPythonの予約語と衝突した場合の対処法です。たとえばsumという変数を使いたいものの、これは関数として存在しています。このような場合は変数名の後ろに _ をつけて対処することが多いです。今回はsum_になりますね。
いくつかの代表的なものを記載しましたが、これ以外にもいくつか存在します。詳細については本家のドキュメントをご参照ください。
コードのレイアウト
変数名の次に気を配るべきなのはコード自体のレイアウトです。たとえば、インデント(字下げ)をどうするかであったり、どういうようなときに空行をいれるかといったものです。
インデント
インデントの基本は半角の空白を4つです。インデントのレベル(深さ)に応じて、4、8、12、16……と増えていきますが、あまりにも深くなるようであれば、アルゴリズムを見なおしたり、関数として外に出すなりすべきです。特に制約がなければ、これさえ守れば通常は問題がおきません。
よくあるのがタブを使うというケースです。これも間違いではないのですが、タブが実際にどれだけのスペースを取るかは推測しがたいですし、空白ほど明白なものではないため避けたほうが無難です。ただ、タブを入力するのは空白ボタンを連打するより楽なので、エディタの機能を使ってタブを半角の空白4つとして入力されるようにしてもいいかもしれません。
ただ、少なくとも空白のインデントとタブによるインデントを混同するのは避けてください。これは環境によってエラーとなります。すでに書かれているコードがタブでインデントされているときはタブでインデントすべきです。許されるのであれば、エディタやコマンドを使ってタブを空白4つに変換してしまってもいいかもしれません。
ほかにインデントで気を配るべきなのは、関数の引数やif文などが長くなり、複数行に分けたい場合です。設計の良し悪しは別にして、引数を8つ以上とる変数は現実に存在します。それを一行に書くと横に長くなってしまいエディタ画面から外に出てしまったり折り返されてしまったりします。このような場合は、インデントを使ってわかりやすい形で関数なりif文なりを表現してください。
たとえば以下のようなものです。
# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# More indentation included to distinguish this from the rest.
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
最初の例では引数を囲む括弧の位置に続く行を揃えていますし、2つめの例では本来よりも深いレベルでインデントさせています。いろいろな方法がありますが、いずれにせよパッと見てわかるようにしてください。
式の空白文字
式で使われる空白にも規則があります。基本的には演算子には空白をつけて、コンマ"," は右に空白、そして括弧類は空白をつけないというのがルールです。たとえば、以下のような書き方は問題ありません。
if(a == b):
my_list = [1, 2, 3, 4]
ただ、以下はあまりよくないです。
if(a==b):
if( a== b):
my_list = [ 1,2,3,4 ]
私が知る限り、これはPython以外のほかの言語でもほとんど同じです。公式のドキュメントにプログラムのサンプルが多数あると思いますので、それに近い空白のつけかたをすることを心がけてください。
一行の長さ
先ほども言いましたが、一行の長さが長くなりすぎると画面の右端からあふれて水平スクロールバーを動かさないと読めなくなったり、左端に折り返してしまってインデントがわかりにくくなったりします。
このようなことを防ぐために、先ほどお伝えしたテクニックなどを使って一行の長さを80あたりに抑えてください。規約次第でこの80という数字は代わりますが、少なくとも環境に依存せず問題が起きない長さにすべきです。
空行
空行はコードのまとまりを表現してくれます。たとえば、以下のコードを見てください。
class MyClass1:
def my_fun1(self):
print('hello')
def my_fun2(self):
print('hello')
class MyClass2:
def my_fun1(self):
print('hello')
これは2つのクラスの宣言です。ただ、空行の入れかたが適切ではないので、コードの区切りがわかりづらいですよね。これを以下のようにするとわかりやすくなります。
class MyClass1:
def my_fun1(self):
print('hello')
def my_fun2(self):
print('hello')
class MyClass2:
def my_fun1(self):
print('hello')
いろいろなルールが存在するのですが、基本的には空行が多いほど区切りが強くなるとおぼえてください。そのため、関数やメソッドの内部のコード、もしくは関数それ自体の区切りはひとつの空行、クラスは2といった形で使われることが多いです。
import
組み込みライブラリや自分が作成したパッケージをimportすることがあります。その際に注意すべきことは、「やたらめったらimportをしすぎない」ということです。必要最小限のimportをしてください。
また、組み込みライブラリ、外部ライブラリ、自分が作ったモジュールなどのimportは順序良く行ってください。どれがどれかわからなくなることを避けるために、複数のimport文の間にグループの境界で空行をいれてあげるのもいいかもしれません。あまり有名でない外部ライブラリを利用するのであれば、それが何なのかコメントを書くのも親切かもしれませんね。
文字コード
Python2の文字コードはASCIIもしくはUTF-8にすべきです。Shift-JISなどは日本でしか利用されないものなので、可能な限り避けるべきです。一方、Python3からはUTF-8で統一することが推奨されています。文字コードはファイルの先頭で必要に応じて宣言する必要があります。
規約より可読性
これまでお伝えしたようにさまざまな規約があり、それを守ることにより可読性が向上します。ただ、規約に固執するあまりに可読性をないがしろにするということは避けてください。これらのルールに反しても読みやすさを優先すべきです。
初心者のうちは「ほかの人がどう書いているか」を見て、上手な人の書き方を真似てみるのがいいかもしれません。ある程度書けるようになったら、どう書いたら読みやすいかを意識して書いてみてください。
今回でPythonプログラミング入門の連載は終了となります。全36回という長期連載となりましたが、最後まで読んでいただけて幸いです。
プログラミングは「本やドキュメントを読む」「人のコードを読む」「自分でコードを書く」ことで上達します。私が知る限り、プログラミングができるようになりたいのにいつまでも書けない人は「本ばかり読んでいる」場合と、「よく理解せず低レベルのコードを量産している」場合が多いような気がします。
今の自分がどうなるべきかをしっかり理解し、それに応じた学習方法を取り込むことがプログラミングスキルの向上の第一歩かもしれませんね。みなさまの楽しいプログラミングライフを願いつつ、連載を終了させていただきたいと思います。今までありがとうございました。
また別の連載があった場合はそちらもお願いします(笑)。
執筆者紹介伊藤裕一(ITO Yuichi)シスコシステムズでの業務と大学での研究活動でコンピュータネットワークに6年関わる。専門はL2/L3 Switching とデータセンター関連技術およびSDN。TACとしてシスコ顧客のテクニカルサポート業務に従事。社内向けのソフトウェア関連のトレーニングおよびデータセンタとSDN関係の外部講演なども行う。 もともと仮想ネットワーク関連技術の研究開発に従事していたこともあり、ネットワークだけでなくプログラミングやLinux関連技術にも精通。Cisco社内外向けのトラブルシューティングツールの開発や、趣味で音声合成処理のアプリケーションやサービスを開発。 Cisco CCIE R&S, Red Hat Certified Engineer, Oracle Java Gold,2009年度 IPA 未踏プロジェクト採択 詳細(英語)はこちら |
---|