この記事を書くきっかけ
Pythonでプログラミングの問題を解くときや、Webアプリケーション作成に取り組むとき、始めたばかりの頃は希望の結果を得ることが最優先でした。プログラムを書くことに慣れていないので、正しい書き方や美しい書き方に気を配る余裕はありませんでした。
エラーやバグがなければとりあえずOKとしていましたが、他人に自分のコードを見られるかもしれないときに、変な書き方をしていたら恥ずかしいと思っていました。
個人開発ではなく、複数人での開発では、多くの人がプログラム開発に携わり、コードを共有します。その場合、他人が自分のコードを判断したり、修正したりする際に、読みにくいコードだと負担をかけてしまいます。
そこで、最低限のプログラム書式だけは早いうちに知っておいた方がいいと思い、プログラミング・スタイルについて勉強することにしました。あくまで、自分が「これは最低限覚えておいた方がいい!」と思ったものに限っています。詳細は公式ドキュメントを参考にしてください。
PEP8とは何か
PEP8は、Pythonのコードを書く際に従うべきガイドラインを定めた公式文書です。PythonコードのスタイルガイドとしてPythonのコーディング規約を定義しています。
PEPの意味
「Python Enhancement Proposal」の略。Pythonの開発プロセスにおける提案や改善案を示す文書のこと。
Python: Pythonプログラミング言語。
Enhancement: 改善や拡張、強調。
Proposal: 提案。
PEPの種類
PEP1: PEPの執筆、フォーマット、プロセスに関するガイドライン。
PEP8: Pythonのスタイルガイド。
PEP20: Pythonの哲学「Zen of Python」。
つまり、PEP 8は「Python Enhancement Proposal」の中で8番目の項目である「Pythonコードのスタイルガイド」を指しています。PEPには他にもさまざまな項目が含まれています。
ちなみに、PEP20はPythonの設計と開発における基本的な哲学を示す短い文書です。この文書は19のシンプルな格言から成り立っていて、Pythonのデザイン哲学を要約しています。
(一部)
- Beautiful is better than ugly.(美しい方が醜いよりも良い)
- Explicit is better than implicit.(明示的である方が暗黙的であるよりも良い)
- Simple is better than complex.(シンプルである方が複雑であるよりも良い)
- Complex is better than complicated.(複雑である方が入り組んでいるよりも良い)
- Readability counts.(可読性は重要)
この部分を読むだけでも、「Pythonはこういう考え方をもとに設計されているんだ」と理解できて面白いです。格言自体もとてもシンプルです。
なぜPEP8を守った方がいいのか
1. 可読性の向上
- 一貫したスタイルでコードを書くことで、他の開発者がコードを読みやすく理解しやすくなるから
- 規定されたスタイルに従うことで、コードが見やすくなり、どの部分が何をしているのかを直感的に理解しやすくなるから
2. チーム開発の効率化
- チーム全体で同じスタイルガイドに従うことで、コードレビューや共同作業がスムーズに進むから
- 複数の開発者が関わるプロジェクトで、コードの整合性が保つため
3. メンテナンスの容易さ
- 可読性の高いコードは、バグや問題を早期に発見しやすくなるから
- スタイルガイドに従ったコードは、将来的な変更や拡張が容易になる。なので、新しい開発者がプロジェクトに参加する際も、理解がスムーズになるというメリットがある
自動ツールの利用
- autopep8やblackなどのツールを使うことで、自動的にPEP8に準拠したフォーマットに整えることができます。手動でスタイルを調整する手間が省けます。
- pylintやflake8などの静的解析ツールは、PEP8に準拠しているかどうかをチェックしてくれます。
自動で整えてくれるツールもあるのですね。いつか使ってみたいです。
PEP8の書き方
インデント
スペース4つを使います。タブは使用しません。
def example_function():
if True:
print("Hello, World!")
行の継続
1行の最大長は79文字までにします。ただし、コメントやドキュメンテーション文字列(docstring)は72文字までにします。行が長くなる場合は、次のいずれかの方法で行を継続します。
(), [], {} 内のルールを使う
Pythonではリストや辞書は(), [], {} 内で複数行に分けることができます。このルールにより、野外条件式や計算式も()で囲んで複数行にできます。
if (10 <= age and age <= 20
or age == 25):
「\(バックスラッシュ)」を使う
「\(バックスラッシュ)」の後に空白をおくと、行を継続するとみなされないので、「\」の直後で改行することができる。ただし、「\」での改行はあまり推奨されない。
total = item_one + item_two + item_three + \
item_four + item_five
改行する位置
長い条件式や計算式を複数行に分ける場合、二項演算子(+,-など)、論理演算子(and,orなど)が行の先頭になるように改行する。
# 良い例
total = (first_variable
+ second_variable
- third_variable)
# 悪い例
total = (first_variable +
second_variable -
third_variable)
空白文字の使い方
二項演算子の前後にスペースを1つ入れる
a = b + c
x = (y * z) - 1
コンマ、コロン、セミコロンの後にはスペースを入れる
if x == 4: print(x, y); x, y = y, x
関数の引数リストの括弧の内側にはスペースを入れない
# 良い例
def my_function(param1, param2):
print(param1, param2)
# 悪い例
def my_function( param1, param2 ):
print( param1, param2 )
スペースを入れてはいけないもの
# 部分範囲を示す「:」
text[2:5]
# 文の区切りの「:」の前後
if a < 0:
# デフォルトパラメータの「=」
print(a, sep=",")
命名規則
- 変数名、関数名、メソッド名はすべて小文字で、必要に応じてアンダースコアで単語を区切る(例:s_list)
- 定数は大文字でつける(例:N)
- クラス名の先頭は大文字(例:MyClass)
- 「l(小文字のエル)」,「O(大文字のオー)」,「I(大文字のアイ)」は単独の識別子にしない(数字と見間違えるから)
- sumやmax、minなどは組み込み変数として存在するので、変数で使いたいときは工夫する(例:sums,sum_valueなど)
インポート
標準ライブラリ、サードパーティライブラリ、自分のモジュールの順にインポートする
import os
import sys
import requests
from mymodule import myfunction
1行に1つのモジュールをインポートする
# 良い例
import os
import sys
# 悪い例
import os, sys
空行
- トップレベルの関数とクラスの定義の間には2つの空行を入れる
- クラス内のメソッド定義の間には1つの空行を入れる
def top_level_function():
pass
class MyClass:
def __init__(self):
pass
def method_one(self):
pass
def method_two(self):
pass
コメント
コメントはコードを分かりやすくするために適切に使う。「#」の後にスペースを1つ入れる。
ブロックコメント
行先頭からのコメント。複数行に渡ってそのコメントが意味のある場合に使う。
# この関数はデータを初期化し、処理を開始します。
# データの初期化には時間がかかる場合がありますが、
# 処理が完了するまで待機する必要があります。
def initialize_and_process_data(data):
initialize_data(data)
process_data(data)
インラインコメント
行の途中からのコメント。文と「#」の間は2つ以上の空白を入れる。その行に関係する場合に使う。
x = x + 1 # 変数xを1増やす
# ループの各ステップでyを2倍にする
for i in range(10):
y = y * 2 # ここでyを更新
その他の規則
関数やクラスの定義の前には必ずコメントやdocstring(ドック・ストリング)を入れる
docstringとは、Pythonプログラムの関数、クラス、モジュールの最初に記述される文字列リテラル(コードに直接書かれた文字列)のことです。その関数やクラス、モジュールが何をするのか、どのように使うのかを説明します。他の開発者がコードの目的や動作を理解する助けになります。
docstringの特徴
- 3つのダブルクオートまたはシングルクオートで囲まれた文字列リテラル
- 関数、クラス、モジュールの最初に記述される
- 複数行に渡ることができる
def add(a, b):
"""
2つの数値を加算し、その結果を返す関数。
Args:
a (int): 最初の数値
b (int): 2番目の数値
Returns:
int: 加算結果
"""
return a + b
コメントとDocstringの違い
コメント
目的: コードの特定の部分の動作や意図を説明すること
使い方: 「#」で始まり、コードの行やブロックの中に挿入される
主な用途
- コードの意図や動作を説明する
- 一時的な注釈やメモを残す
Docstring
目的: 関数、クラス、モジュールを説明をすること。特に、これらの要素が何をするのか、どのように使うのかを説明する。
使い方: 関数、クラス、またはモジュールの最初に書かれ、3つのダブルクオート (""") またはシングルクオート (''') で囲む。
主な用途
- APIの利用方法や意図を説明する
- 自動生成されるドキュメントの情報源として利用される(ドキュメント生成ツール(例:Sphinx)がdocstringを読み取り、自動的にHTMLやPDFなどの形式でドキュメントを生成することができる)
まとめ
何度もコードを書いているので、「それはさすがに知っているよ」というものばかりでした。しかし、個人的にいくつかPEP8を守っていない書き方をしていることに気づきました。
例えば、「l(小文字のエル)」を変数で多用していたり、if文の条件式を一行に79文字以上続けて書いていたり、import文のimportの順番がめちゃくちゃだったり、インラインコメントとブロックコメントを全然使い分けていなかったり。
細かいこととはいえ、一度知っておけば今後も正しい書き方を継続できるので、今回勉強できてよかったと思っています。時間が空いたら、PEP8も他の書き方も見てみたいと思います。