Python にまつわるアイデア: PEP 8

PEP 8 とは「 Style Guide for Python Code 」ーー Python コードの「書き方ガイド」です。

コードは一般に「書かれる時間」よりも「読まれる時間」の方が長いという事実に基づいて、「スタイルを統一し読みやすいコードを書こう」というアイデアのもとに作られたのがこのガイドです。

レイアウトなどの大きな視点のお話から空白やコメントの使い方といった細かなポイントまで、「こういうときにはこう書こう」という規約が数多く提案されています。

ボリュームが多いのでここではその一部だけをご紹介したいと思います。詳細を確認したい場合はぜひ原文をご確認ください。他の言語で書くときにも参考になる規約です。

まずはレイアウトまわりのポイントから。

レイアウト

インデントは「スペース4つ」で統一すること。

OK:

for e in li:
    print e  # スペース4つ

NG:

for e in li:
  print e  # スペース2つ

文の途中で改行する場合は、括弧の直後で縦のラインをあわせること。

OK:

foo = long_function_name(var_one, var_two,
                         var_three, var_four)

文の途中で改行する場合、空白行をはさまず直後に次の文がくる場合は、区切りがわかりやすいよう、改行後のインデントを落とすこと。

OK:

def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

一行の最大文字数は79文字とすること。

行が長くなる場合は、 () をうまく使って改行すること。できれば \ (バックスラッシュ)ではなく () を使うこと。

演算子のところで改行する場合は、演算子の前ではなく「後」で改行すること。

OK:

y = a + b + c + \
    d + e + f + g

NG:

y = a + b + c \
    + d + e + f + g

トップレベルの関数やクラスの定義ブロックの前後には2行空行を入れること。

OK:

class A(object):
    # contents of A

class B(object):
    # contents of B

クラスの中のメソッド定義の前後には1行空行を入れること。

その他、ロジカルな塊を区別するために空行を使うこと。

文字エンコードには ASCII か Latin-1 エンコーディング ( ISO-8859-1 )を用いること(PEP0263)。 Python 3.0 以降は UTF-8 を用いること(PEP 3120)。

import 文は原則 1 行にまとめず、モジュールごとに分けて書くこと。

OK:

import os
import sys

NG:

import sys, os

ただし、クラス名などをまとめてimportするのはOK。

OK:

from subprocess import Popen, PIPE

import 文はコードの一番最初に書くこと。

モジュールの import はおおよそ次の順番で行うこと。

  1. 標準ライブラリ
  2. サードパーティライブラリ
  3. ローカルライブラリ

半角スペース

各種かっこ( () [] {} )の中の両端ではスペースを空けないこと。

OK:

spam(ham[1], {eggs: 2})

NG:

spam( ham[ 1 ], { eggs: 2 } )

コンマ、コロン、セミコロンの直前ではスペースを空けないこと。

OK:

a, b = c, d;
{"key": "value"}

NG:

a , b = c , d ;
{"key" : "value"}

()[] の直前にはスペースを空けないこと。

OK:

spam(1)
dict['key'] = list[index]

NG:

spam (1)
dict ['key'] = list [index]

縦のラインをあわせるために代入( = )の前後で連続スペースは用いないこと。

OK:

x = 1
y = 2
long_variable = 3

NG:

x             = 1
y             = 2
long_variable = 3

各種演算子( + - * / == in not is )の前後にはスペースをひとつ入れること。

OK:

i = i + 1
submitted += 1

NG:

x = x*2-1

hypot2 = x*x + y*y
c = (a+b) * (a-b)

ただし、関数のキーワード引数の場合の = には前後にスペースを入れないこと。

OK:

def complex(real, imag=0.0):
    return magic(r=real, i=imag)

; 」を使えば複数の文を1行に入れることができるがそれは使わないこと。

コメント

コメントを最新に保つこと。

コメントが文である場合は、最初の文字は大文字で始めること。

英語圏以外の人も、そのコードが同じ言語圏の人にしか読まれないと 120% 言い切れる場合を除き、コメントは英語で書くよう努めること。

public なモジュールや関数には必ず docstring をつけること。

バージョン管理

OK:

__version__ = "$Revision: 16dd63848921 $"
# $Source$

変数名のつけ方

さまざまな変数名のスタイルをしっかりと使い分けること。

  • 小文字( lowercase
  • 大文字( UPPERCASE
  • アンダースコアつき小文字( lower_case_with_underscores
  • アンダースコアつき大文字( UPPER_CASE_WITH_UNDERSCORES
  • 大文字始まり( CapitalizedWords
  • 2つめの単語以降大文字始まり( mixedCase

_ 始まりなどの変数名には特殊な意味があることを認識して使うこと。

モジュール名は原則すべて小文字( lowercase )で。可読性を高めるために _ を使ってもよい。

クラス名は大文字始まり( CapitalizedWords )で。

関数名は、原則すべて小文字( lowercase )で。可読性を高めるために _ を使ってもよい。

メソッドの最初の引数の名前は、インスタンスメソッドは self 、クラスメソッドは cls を使うこと。

定数名は、アンダースコアつき大文字( UPPER_CASE_WITH_UNDERSCORES )にすること。

その他

例外処理の try 文の中身は、できるかぎり小さいまとまりにすること。

OK:

try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

NG:

try:
    # Too broad!
    return handle_value(collection[key])
except KeyError:
    # Will also catch KeyError raised by handle_value()
    return key_not_found(key)

例外処理の except 文では例外の種類をできるかぎり明示すること。

OK:

try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

NG:

try:
    import platform_specific_module
except:
    platform_specific_module = None

シーケンス(文字列・リスト・タプル)が空かどうかを判定するときは、空シーケンスは False となる事実を使ってシンプルに書くこと。

OK:

if not seq:

NG:

if len(seq)

・・・以上です。

コードの書き方やスタイルではなく、プログラムのより本質的な部分である「アルゴリズム」や「ロジック」に集中するためには、このようなあらかじめまとめられたルールを踏襲するのがよいかと思います。ただし、それも場合によりけりで、たとえば次のようなケースでは「このルールをムリに適用しない方がよいかもね」と PEP 8 の中でも言及されています。

  • ルールを適用するとかえって読みづらくなる場合
  • 既存のコードがこのルールに従っていない場合

繰り返しになりますが、ここにあるのがすべてではないので(また、正確でなかったり間違っていたりもするかもしれないため)、詳細の確認は原文にあたっていただければと思います。

参考