PEP8の基本事項をわかりやすく端的にまとめてみた

## はじめに
Python コミュニティでは、コードの可読性や一貫性を向上させるために、PEP8と呼ばれる公式のスタイルガイドを採用されている。PEP8は、Pythonのコードを書く際の一般的な規約やベストプラクティスをまとめたものであり、他のPython開発者とのコードの互換性を保つために重要である。

https://pep8-ja.readthedocs.io/ja/latest/

本記事はPEP８の基本事項をわかりやすく端的に伝えるために、以下の順序で説明を行う。

1. 命名方法
1. 空白文字
1. インデント
1. 改行
1. 空行
1. import
1. その他


## 命名方法
### クラスの名前
クラスはCapWords形式で書く。(ex `CapitalizedWords`) 

### 関数や変数の名前
関数と変数は小文字のみとし。単語をアンダースコアで区切る。

### 引数
インスタンスメソッドのはじめの引数の名前は`self`、
クラスメソッドのはじめの引数の名前は`cls`を使うべきである。

### 定数
定数は全て大文字で書き、単語をアンダースコアで区切る。(ex `TOTAL`)

### 冒頭及び末尾にアンダースコアを含む名前
- 冒頭に一つのアンダースコア(`_a`)
    内部でのみ使用することを示す。`from M import *`でインポートされない

- 冒頭に二つのアンダースコア(`__a`)
    クラスの属性に名前を付けるときに、名前のマングリング機構を呼び出す。（つまりクラス`Foo`の`__boo`という名前は `_FooBar__boo`になる。）

- 末尾に一つのアンダースコア(`a_`)
    Python のキーワードと衝突するのを避けるために使われる。(ex,`input_ = 1`)

- 冒頭と末尾に二つのアンダースコア(`__a__`)
    ユーザーが制御する名前空間に存在する "マジック"オブジェクト または "マジック"属性を示す。(ex`__init__`)

### 例外の名前
例外はクラスで定義し、末尾に`Error`と付けるべきである。

## 空白文字
### 空白文字を使うべきケース

空白文字を使うべきケースは以下である。

1. 演算子(ex `=`)の両側(例外あり)

```Python
# 空白文字を使うべきケース
a = 1 #例1
b = a + 1
```

ただし優先度が異なる演算子があった場合には、優先順位が一番低い演算子の両側にのみスペースを入れる。

```Python
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
```

また演算子の両側であるにも関わらず空白を入れてはいけないケースは次で述べる。

### 空白文字を使ってはいけないケース

空白文字を使ってはいけないケースは以下である。

1. 括弧やブラケット、波括弧のはじめの直後と終わりの直前
1. 末尾のカンマと、その後に続く閉じ括弧の間
1. カンマやセミコロン、コロンの直前
1. 関数呼び出しの引数リストをはじめる開き括弧の直前
1. インデックスやスライスの開き括弧の直前
1. **アノテーションされていないキーワード引数**


```Python
#空白文字を使ってはいけないケース
spam( ham[ 1 ] ) #例1 (正)　spam(ham[1])

bar = (0, ) #例2 (正)　　bar = (0,) 

x , y = y , x #例3 (正)　　x, y = y, x
def func(val : int):  #例3 (正)　　def func(val: int): 

spam (1) #例4 (正)　　spam(ham[1])

dct ['key'] = 1 #例5　(正)　dct['key'] = 1


def complex(real, imag = 0.0):
    return magic(r = real, i = imag)
"""
#例6 (正)
def complex(real, imag=0.0):
    return magic(r=real, i=imag)
"""
```

例６は、先ほどの演算子の両側であるにも関わらず空白を入れてはいけないケースである。

また演算子の位置を揃えるために、演算子の周囲に1つ以上のスペースを入れてはいけない。

```Python
y             = 2　　#例6 (正) y = 2　
long_variable = 3　
```

## インデント
### インデントの基本ルール

インデントのルールは以下である。

1. 開き括弧を揃える
1. 引数とそれ以外を区別するため、スペースを4つ(インデントをさらに)加える（関数でも後述）
1. 突き出しインデントはインデントのレベルを深くする、ただし突き出しインデントの場合は４つスペースは使わなくて良い

```Python
# 開き括弧に揃える
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# 引数とそれ以外を区別するため、スペースを4つ(インデントをさらに)加える
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# 突き出しインデントはインデントのレベルを深くする、ただし突き出しインデントの場合は４つスペースは使わなくて良い
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
```

### if文でのインデント
`if`文の条件部分が長い場合は以下のように記述する。

```Python
# 追加のインデントをしない
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# シンタックスのハイライトをサポートするエディタで区別するため
# コメントを追加する
if (this_is_one_thing and
    that_is_another_thing):
    # 両方の条件がtrueなので、処理を調整可能
    do_something()

# 継続された行の条件をインデントする
if (this_is_one_thing
        and that_is_another_thing):
    do_something()
```

## 改行
演算子を含む改行の際は、演算子とオペランドを近づけて書く。

```Python
# 演算子とオペランドを一致させやすい
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)
```

また1行の文字数は最大79文字までとし、超えた場合は改行する。
また改行する場合は読みやすさを考慮する。

## 空行
トップレベルの関数やクラスは、2行ずつ空けて、クラス内部では、1行ずつ空けてメソッドを定義する。

```Python
Class A:
    def __init__(self):
        pass
    
    def method(self): #上のメソッドと1行空ける
        pass


Class B: #上のクラスと２行開ける
    pass
```


## import
importの基本ルールは以下である。

1. 複数のライブラリをimportする際は改行する。
1. `from lib import A,B`のように一つのライブラリから複数インポートする場合はOK。
1. `from lib import *`のようにワイルドカードは名前空間がわかりにくくなるので使わない。

ライブラリのインポートは以下の順序で行う。

1. 標準ライブラリ(ex.`os`)
1. サードパーティに関連するライブラリ(ex.`numpy`)
1. ローカルのライブラリ


## その他
### ソースファイルのエンコーディング
UTF-8に統一し、エンコーディング宣言はしない

### カンマ
末尾のカンマは通常任意だが、要素数が一つのタプルでは例外的に必須である。(ex `a = (1,)`)

### コメント、docstring
コメントは複数の完全な文で書くべきであり、大文字から始めること。
インラインは控えめに使うこと。

docstringは、すべての公開されているモジュールや関数、クラス、メソッドには必須である。
docstring が1行で終わる場合は、同じ行を """ で閉じる。

### `None`であるかどうかの比較
`None`であるかどうかの比較は`is not`を用いて`if foo is not None:`とする。

### return文の一貫性
関数の中の全てのreturn文は式を返すか、全く何も返さないかのどちらかにすべきである。
また式を返しているreturn文が関数内にある場合は明示的に`return None`と書くべきである。

### 文字列のprefix,suffix
文字列のprefix,suffixはスライシングではなく、`startswith()`,`endswith()`を用いて確認する。

### オブジェクトの型比較
オブジェクトの型比較は`type`を用いず、`isinstance()`を用いる。

## 最後に
本記事ではPEP８の基礎事項に関してまとめた。ただPEP８にも記載されているが、PEP8はあくまでガイドラインであり、必ずしも全てのルールに厳密に従う必要はない。

読みやすくわかりやすいPythonのコードを書いていきましょう。


## 本記事でPEP8で触れなかった内容
- 継承の設計
- 公開インターフェイスと内部インターフェイス
- 拡張比較について
- 詳しい例外の処理
- コンテキストマネージャー