PEP8 について学習しました。このテキストの内容は PEP8 の正確な「翻訳」ではなく、自分が内容を理解するために(自分用に)調整した「意訳」版です。
原文の PEP8 では、文章だけで説明される規則に対して、独自のサンプルを追加しているものもあるので注意。
日本語版でもよいのかもしれないのですが、python は、詳しくないこともあって、どうも意味がよくわからないところがあって、自分で調べて勉強することにしたものです。
Introduction(はじめに)
このドキュメントでは、Python の main distribution の標準ライブラリを構成する Python のコードのコーディング規約 (coding conventions) を示します。Python の C 実装における C コードのスタイルガイドライン については PEP7 を参照すること。
このドキュメントと PEP257 (Docstring Conventions) は Guido 氏の作ったオリジナルの Python Style Guide に Barry 氏のstyle guide をいくつか加えた内容になっています。
これらの style guide は、時間の経過と共に進化します。言語自体の変更によって、過去の規則が廃止されたり、追加の規則があります。
多くのプロジェクトでは、独自の coding style guideline を持っています。矛盾が生じたときは、そのプロジェクト固有のガイドを採用してください。
A Foolish Consistency is the Hobgoblin of Little Minds(愚かな一貫性は小さな心のホブゴブリン)
Guide 氏の重要な洞察のひとつは、コードは書かれることよりも読まれることのほうがずっと多いということです。ここで提供される guideline は、コードの読みやすさを改善し、python のコードの広い範囲で一貫性を持たせることを目的としています。PEP20 が言うのところの "Readability counts" です。
style guilde とは、一貫性のことです。この style guide と共に一貫性 (consistency) は重要です。プロジェクトの中での一貫性はもっと重要です。ひとつの module や function の中での一貫性がもっとも重要です。
しかしながら、矛盾が生じることを知っておくーーなんらかの style guide の推奨することが提供できないことがある。迷ったときは、あなたの best judgment をします。他の例を見て、なにがベストか決めてください。そして、躊躇わずに聞いてみること!
特に注意すべき点:この PEP に準拠するためだけに、後方互換 性を壊さないこと!
特定の guideline を無視するいくつかの理由もある:
このガイドライン を適用することで、この PEP に従ったコードに読みなれている人であっても、コードが読みにくくなるケース
(歴史的な理由から)guideline を破っているまわりのコードとの整合性を取るケースーーただし、それは他人の書いたコードを改善する機会でもある(本物の XP = extreme programming スタイルでいこう)
もしも、そのコードが guideline を導入する以前に書かれたものであり、また、そのコードを変更する他の理由がないケース(=それを今すぐに直す必要はない)
styleguide が推奨する機能をサポートしていない古いバージョンの python との互換性を保つ必要があるケース
Code Lay-out
Indentation
indent は、レベルごとに4つの space " "
を使うこと。
改行されてしまう(複数行の)コードは ()
か []
か {}
の括弧を使って、複数行にして、要素を縦に揃える、または、ぶら下がりインデント hanging indent を使って整列させるべきです。ぶら下がりインデントを使うときは、次の点に気をつけること;最初の行には引数を書かず、継続行であることが明確に区別するため、さらに字下げ indent をすること:
footnote: ぶら下がりインデント hanging indent とは、段落内のすべての行が最初の行を除いて indent される style です。python での、ぶら下がりインデントという用語は、括弧付き文 parenthesized statement において、「1.開き括弧で行の終わりにあること」、「2.次の行から閉じ括弧までを indent する」この style のことを指します。
foo = long_function_name(var_one, var_two,
var_three, var_four)
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)
foo = long_function_name(var_one, var_two,
var_three, var_four)
def long_function_name (
var_one, var_two, var_three,
var_four):
print (var_one)
継続行における 4-space のルールは必須ではありません。
任意の例:
foo = long_function_name(
var_one, var_two,
var_three, var_four)
if 文の条件部分が長くて複数行にまたがるとき、if
という2文字のキーワードとひとつの
(スペース)そして (
を組み合わせると if (
になってしまい、自然と 4-space されるため、視覚的に紛らわしい状態を生む恐れがあります。
PEP8 では、そうした条件式と nest された code block をさらに視覚的に区別する方法(あるいは、区別するかどうか)については、明確な方針を示していません。このようなときに許容される選択肢には、次のようなものがありますが、これに限るものではありません:
if (this_is_one_thing and
that_is_another_thing):
do_something()
if (this_is_one_thing and
that_is_another_thing):
do_something()
if (this_is_one_thing
and that_is_another_thing):
do_something()
(後述の binary operators の前後で break するかどうかの議論も参考にすること)
{}
[]
()
の括弧は、複数行にまたがるとき list の最終行の文字に揃えることができます。次のような書き方になる:
my_list = [
1 , 2 , 3 ,
4 , 5 , 6 ,
]
result = some_function_that_takes_arguments(
'a' , 'b' , 'c' ,
'd' , 'e' , 'f' ,
)
あるいは、複数行を開始する行の最初の文字の下に揃えることもできます:
my_list = [
1 , 2 , 3 ,
4 , 5 , 6 ,
]
result = some_function_that_takes_arguments(
'a' , 'b' , 'c' ,
'd' , 'e' , 'f' ,
)
Tabs or Spaces?(インデントは tab 文字かスペースの文字か)
space
は望ましい indent の方法です。tab \t
はすでに tab 文字で indent されてしまっている code との一貫性を保つためだけに使うべきです。
python では tab と space を混ぜて indent をすることを禁止しています。
Maximum Line Length(1行の最大文字数)
1行の最大文字数は 79 文字に制限します。(プログラムにおける構文などの)構造的な制約がすくないテキストブロック (docstring や comment) の長さは 72 文字に制限するべきです。
editor の window 幅の要件を制限することで、複数ファイルを並べて開くことができるようになります。(異なる)ふたつのバージョンのコードを、左右に並べて表示する code review のツールを使うときにも適しています。
多くの tool の自動折り返し機能は、コードの視覚的な構造を乱してしまうので、コードを理解しづらくします。ここまでの制限ルールは 80 文字の幅に設定された editor で折り返しが発生しないようにするものです。79文字にする理由は、80文字目に marker glyph として →
や ↩
や …
の記号を加えて入れる機能があるので、(最後の1文字が隠れることになるのを)それを避けるためです。また、一部の web tool では、自動折り返し機能自体が無いこともあります。
チームよっては、行の文字数が長いことを好むこともあります。ここまでの指摘を許容することができるチームなら、行の長さの制限を 99 文字まで増やしてもよいです。しかし、docstring と comment は 72 文字で折り返してください。
python の standard library は保守的です。行を 79 文字に制限することを要求します。docstring/comment は 72 文字です。
長い行を折り返すときは括弧 ()[]{}
の中で python の暗黙的な行継続を利用します。長い式は括弧で囲むことで複数の行に分割できます。この方法は backslash \
を使った継続よりも好ましいです。
backslash \
を使うほうが適切なケースもあります。例えば、python 3.10 よりも以前は with
を使った長いコードでは backslash の使用が許容されていました。
with open ('/path/to/some/file/you/want/to/read' ) as file_1, \
open ('/path/to/some/file/being/written' , 'w' ) as file_2:
file_2.write(file_1.read())
with (
open ("file1" ) as f1,
open ("file2" ) as f2
):
(このような複数行の with
statement の indent については、複数行の if
statement に関する話を参考にすること)
もうひとつのケースは assert
statement です。続きの行を適切に indent してください。
(以下は勝手に追記している)おそらく:
assert (
some_long_condition and
another_condition
)
assert some_long_condition and \
another_condition
assert (
user.is_authenticated and
user.has_permission("edit" )
), "User must be authenticated and have edit permission"
assert some_long_condition and
another_condition
Should a Line Break Before or After a Binary Operator?(binary operator の前後で改行すべきか?)
何十年もの間 binary operator の後で改行することが推奨されていました。しかし、演算子 は画面上の異なる位置に散らばる傾向があり、各演算子 は operand から離れて前の行に移動しています。
なので、どの項目が加算されて、どの項目が減算されたのかを見分けるためには、目は面倒な動作をすることになる。
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
この読みやすさの問題を解決するために、数学者と出版社は反対の慣例に従っています。Donald Knuth は彼の Computers and Typesetting シリーズでルールを説明しています:"段落内の(インライン)数式は binary operator の後で改行され、ブロック形式の (displayed) 数式 は operator の前で改行される"(Tex の話)
数学の伝統に従うことで、通常は読みやすいコードになります:
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
python のコードでは、binary operatorの前後で行を折り返すことが許容されています。ただし、locally(≒ そのscope, block、module, function のような狭い範囲)において style が一貫している限りです。
Blank Lines(空白の行)
top-level の関数とクラス定義を2行の空白行で囲むこと。
def func1 ():
pass
class MyClass :
pass
class 内の method 定義は1行の空白行で囲むこと。
class MyClass :
def method1 (self):
pass
def method2 (self):
pass
関連する関数のグループを区切るために、余分な空白行を(sparingly ≒ 控えめに)使用してもよい。空白行は、関連する1行だけの関数が連続するときは、省略してもよい。(例えば、ダミー実装のセット)
def load_user_data ():
pass
def validate_user_data ():
pass
def load_product_data ():
pass
def validate_product_data ():
pass
def save_results ():
pass
def noop1 (): pass
def noop2 (): pass
def noop3 (): pass
関数内の空白行は、論理的な section を示すため控えめに使用すること。
python では control+L
= home feed の文字も空白文字として受け付けています。多くのツールでは、区切り文字として認識するので file 内の大きな section を区切りたいときに使うことができます。Note, 一部の editor や web 上の code reviewer では control-L
を home feed として認識せずに別の記号を表示することがある。(互換性に注意する必要があるということ)
空白行は、意味のある区切りとして使うというあたりが PEP8 の sparingly ≒ 控えめに、の意図だと思います。
Source File Encoding
python の core distribution のコードは UTF-8 を使うべきです。encoding declaration は持つべきではありません。
encodiong declaration = XML だと <?xml version="1.0" encoding="UTF-8 "?> のようなものをファイルの先頭に記述すること。python も encoding declaration = エンコード 宣言ができる。
標準ライブラリの中では UTF-8 以外の encoding はテスト目的でのみ使用するべきです。非 ASCII 文字の使用は控えめにして、できれば地名や人名などに限るべきです。データとして非 ASCII 文字を使うときは z̯̯͡a̧͎̺l̡͓̫g̹̲o̡̼̘ のようなノイズの多い Unicode 文字や BOM の使用は避けること。
python の標準ライブラリの中では識別子(変数名や関数名など)は ASCII のみで書くことは MUST です。そして、できるだけわかりやすい英単語の名前を使うのは SHOULD です。
世界中に利用者のいるオープンソース のプロジェクトは、同様の方針を採用することが推奨されます。
Imports
import os
import sys
import sys, os
とは言っても、このようにしても OK です(同じモジュールから複数の機能を import する例):
from subprocess import Popen, PIPE
import は必ずファイルの一番最初に書かれます。モジュールに対する comment や docstring のすぐ後であり、module の globals や constaints の前です。
import os
import sys
from datetime import datetime, timedelta
from typing import Optional
SESSION_TIMEOUT = 3600
DEBUG_MODE = True
def sample (username: str , password: str ) -> bool :
import は以下の順序でグループ化するべきです:
標準ライブラリ
関連するサードパーティ 製ライブラリ
自作アプリケーション、ライブラリの local module
各グループの間には、ひとつの空白行を入れて区切るべきです。
absolute import が推奨されます。import の仕組みが誤って構成されているとき(例えば、パッケージ内のディレクト リが(紛らわしい)sys.path
に入っているようなケース)でも、適切に動作する(または、少なくとも、わかりやすいエラーメッセージを与えてくれる)傾向にあるからです:
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
しかしながら、明示的な relative import も条件つきでアリです。特に、複雑なパッケージ構成において absolute import だと不必要に冗長になるようなケースだと有効だろう:
from . import sibling
from .sibling import example
標準ライブラリのコードでは、複雑なパッケージ構成そのものを避けて、常に absolute import を使うべきです。
クラスを含むモジュールからクラスを import するときは、つぎの書き方をすると OK です:
from myclass import MyClass
from foo.bar.yourclass import YourClass
もしも、MyClass
や YourClass
の名前が衝突してしまうときは module ごと explicitly ≒ 明示的にします:
import myclass
import foo.bar.yourclass
そして、コードの中では myclass.Myckass
や foo.bar.yourclass.YourClass
のようにして使います。(あくまで、名前が重複するなどの問題があるときの話)
wildcard import from <module> import *
は避けるべきです。その理由は、import してきた機能は、どの名前空間 に存在していのかわからなくなって、コードを読む人もツールも混乱します。
ただし wildcard import に正しさのある使い方がひとつだけあります。それは、internal interface を public API として再公開するために使う場合です。(例えば、ある interface の python の実装を、任意の高速化させたモジュールが存在するときに、それで上書きするようなケースです。どの定義が上書きされるのか事前には、わからない場合に限って import *
が役に立つことがあります)
try :
from ._accelerator import *
except ImportError :
from ._fallback import *
このように名前を再公開するときも、public & internal interface の扱いに関する guideline は以前として適用されます。
Module Level Dunder Names(モジュールレベルの dunder の名前)
dunder name とは、名前の先頭と末尾に underscore を2つずつ持つ __name__
のような特別な名前のことです。これをどこに書くべきか、ということです。dunder = d ou ble under score のこと。口語的なスラング でダンダーが近い発音になる。
例えば __all__, __author__, __version__
などはモジュールの docstring の直後に挿入し import の前に配置するべきです。__future__
からの import は例外で、python は docstring を除いて、コードの一番最初に future-import が現れることが義務付けられています。
"""This is the example module.
This module does stuff.
"""
from __future__ import barry_as_FLUFL
__all__ = ['a' , 'b' , 'c' ]
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
import os
import sys
String Quotes(文字列の quote 処理)
python では single-quote 'string'
と double-quote "string"
の文字列は同じです。PEP8 はどちらを使うべきかについて、特に推奨していません。ルールを決めたら、それを一貫して使ってください。
ただし、文字列の中に single-quote や double-quote が含まれる場合は、escape \
を避けるために、反対の quote を使います。このほうが読みやすいからです。
quote = "I'm happy."
quote = 'He said, "Hi."'
quote = 'I \' m happy.'
quote = "He said, \" Hi. \" "
triple-quote を表現したいときは、PEP257 docsting 規約と一致するように常に double-quote """
を使ってください。
"""This is a docstring."""
Whitespace in Expressions and Statements(expression や statement における空白)
Pet Peeves(気にくわないこと)
次のような状況では、余計な余白の space
を避けること:
spam(ham[1 ], {eggs: 2 })
spam( ham[ 1 ], { eggs: 2 } )
末尾のカンマ ,
と括弧の間も、余計な余白の space
を避けること:
foo = (0 ,)
bar = (0 , )
カンマ ,
、セミ コロン ,
、コロン :
の直前も、余計な余白の space
を避けること:
if x == 4 : print (x, y); x, y = y, x
if x == 4 : print (x , y) ; x , y = y , x
しかしながら、slice 構文では、a[1:9]
のようにコロン :
は binary operator のように振る舞うため、その前後に等しい数の空白を置くべきです。(優先順位が最も低い演算子 と扱われる)extended slice(拡張 slice 構文)では、a[1 : 9 : 3]
のように両方のコロン :
に同じ数の空白を適用するべきです。
例外:slice のパラメーターが省略されているとき a[1:]
は、空白も省略。
ham[1 :9 ], ham[1 :9 :3 ], ham[:9 :3 ], ham[1 ::3 ], ham[1 :9 :]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
ham[lower + offset:upper + offset]
ham[1 : 9 ], ham[1 :9 ], ham[1 :9 :3 ]
ham[lower : : step]
ham[ : upper]
関数の引数リストを開始する括弧の直前は、余計な space
を避けること:
spam(1 )
spam (1 )
indexing や slicing の括弧 []
の前は、余計な space
を避けること:
dct['key' ] = lst[index]
dct ['key' ] = lst [index]
代入演算子 =
の前後は、(他行の演算子 と整列させるために)空白を入れすぎないこと:
x = 1
y = 2
long_variable = 3
x = 1
y = 2
long_variable = 3
Other Recommendations(そのほかの推奨)
末尾の空白 (trailing whitespace) は避けてください。なぜなら、たいていは目に見えないし、混乱を引き起こします。例えば、バックスラッシュ \
の後に space と改行が続いていても、それは改行記号として機能しません。
editor によっては、空白を保存しないものもあるし、(CPython 自身を含む)多くのプロジェクトでは空白を拒否する pre-commit hook(Git などで commit 前に自動で実行されるコードチェック・整形のスクリプト のこと)がある。
binary operator の前後には常に空白をひとつずつ入れること。
assignment =
augmented assignment +=
-=
etc.
comparison ==
<
>
!=
<=
>=
in
not in
is
is not
boolean and
or
not
優先順位の異なる演算子 を組み合わせる場合は、優先順位の低いほうの演算子 の前後に空白を入れることを考慮します。(空白は)あなた自身の判断で使ってもよいのですが、空白は必ず両側に同じ数(通常1個)を入れること。
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
優先度の低いほうの演算子 の前後にだけ space
を入れるため x*x + y*y
のように +
の前後にだけ space
がある。
(あなた自身の判断で space
を使えともあるので)多少のスタイルの揺れは許されると思います。数式が長くなると、このルールの適用が難しいことがあるかもしれません。(長い数式は複数行に分割することも示されている)
関数の annotation は、コロン :
のルールを使用します。戻り値の指定 ->
を使うなら、その前後に space ->
を入れること。(詳細は後述の「Function Annotations」を参照)
def munge (input : AnyStr): ...
def munge () -> PosInt: ...
def munge (input :AnyStr): ...
def munge ()->PosInt: ...
キーワード引数を示す場合や、annotation のない関数パラメータにデフォルト値を指定するときは =
の前後に空白を入れないこと:
def complex (real, imag=0.0 ):
return magic(r=real, i=imag)
def complex (real, imag = 0.0 ):
return magic(r = real, i = imag)
ただし、引数 annotation とデフォルト値を組み合わせるときは =
の前後に空白を使用すること:
def munge (sep: AnyStr = None ): ...
def munge (input : AnyStr, sep: AnyStr = None , limit=1000 ): ...
def munge (input : AnyStr=None ): ...
def munge (input : AnyStr, limit = 1000 ): ...
複合 statement(同じ行に複数の statement を書くこと)は、一般的に推奨されません:
if foo == 'blah' :
do_blah_thing()
do_one()
do_two()
do_three()
if foo == 'blah' : do_blah_thing()
do_one(); do_two(); do_three()
if, for, while を同じ行に書いてもいいことがあります。しかし、複数の節 multi-clause を持つコードのところでは、するべきではないです。また、長いコードを無理に折り返すことも避けること!
if foo == 'blah' : do_blah_thing()
for x in lst: total += x
while t < 10 : t = delay()
if foo == 'blah' : do_blah_thing()
else : do_non_blah_thing()
try : something()
finally : cleanup()
do_one(); do_two(); do_three(long , argument,
list , like, this)
if foo == 'blah' : one(); two(); three()
When to Use Trailing Commas(末尾カンマを使うとき)
末尾カンマが冗長(不要)でも、バージョン管理の仕組みを使用するときは、有用になることがあります。値、引数、import の項目が(将来的に)増えるかもしれないときが該当します。
書き方のパターンとしては、値を1行ずつに書き、末尾カンマを加えて、閉じる括弧 (parenthesis/bracket/brace) と同じ行にカンマを置くのは非推奨。(ただし、singleton tuple を除く)
FILES = [
'setup.cfg' ,
'tox.ini' ,
]
initialize(FILES,
error=True ,
)
FILES = ['setup.cfg' , 'tox.ini' ,]
initialize(FILES, error=True ,)
tuple のような場合は ('tox.ini' ,) にしないと tuple にならない。 ('tox.ini' ) では値になる。
コードと矛盾するコメントは、コメントが無いことよりも悪いものです。コードが変更された時は、常にコメントを最新の状態に保つことを優先すること!
コメントは完全な文章でなければならないです。最初の文字は大文字で始めます。(識別子の大文字小文字は、絶対に変えないこと!)
block comment は、通常だと完全な文章をひとつ以上の段落で構成します。それぞれの文はピリオドで終わるようにします。
複数の文で構成されるコメントでは、文の末尾のピリオドの後に1 or 2の空白を使用する必要があります。
英語を母国語としない国の python corder のコメント:そのコードがあなたの言語を母国語としない人に読まれることは絶対にないことを 120% 確信していない限り、コメントは英語で書いてください。
最後の指摘は unless
x never be read
x by people who don't speak your language
で否定が3つもある文章構造。単に「英語以外で書くな」と示すと言葉として強すぎるので、とても強く制限をかけたい言い回しになっている。120%の確信なんてありえないから、英語で書いてねと読んでおけばいい気がする。(もしくは、あなただけのプライベートなコードなら好きにしたらいい、とも読める)
block comment は一般的に、それに続くコードの一部、または、すべてに適用されます。そして、(コメントを挿入する位置の)コードと同じ位置(レベル)にインデントします。
block comment の各行は #
と、ひとつの space #
から始まります。(コメント内のテキストが、引用、サンプルコードなどの理由で特別なインデントのある場合は別)
block comment 内の段落は "#" だけの1行で区切る。
inline comment は控えめに使うこと。
inline comment とは、statement と同じ行にあるコメントのことです。inline comment は statement から少なくとも2つの space
で区切らなければいけません。inline comment は #
で始めてください。
(コードの内容が)明らかなことを述べるのであれば inline comment は邪魔になります。以下のようなものは書かないこと:
x = x + 1
しかし、役に立つ inline comment もある:
x = x + 1
Compensate for border の意味は、あまり気にする必要はないと思うけど「border の値に+1の補正をする」ようなことを伝えたいように思います。日本語の PEP8 だと「境目を補う」というテキストでした。(私の理解だと)x
は border になるし、加算の意味は(自動詞の)compensate になったし、情報を出しているので人狼 ではない善良な市民の行動に見えます。(これだと関数に対するコメントでよいことも多いはずなので、よく使うものではなくて「控えめに」必要があるときだけ使う)
Documentation Strings
documentation strings(別名: docstrings)を書くための規則は PEP257 に示されています。(are immortalized = 永遠に記録されている)
すべての public module, function, class, method には docstring を書くこと。非公開の method には必要ないけど、処理の内容を説明するコメントは書くべきで def
の行の直後に書く。
def func ():
"""" func comment... """
PEP257 には docstring の規則が書かれています。最も重要なことは、複数行の docstring の最後を示す """
は、単独の1行にして書くこと。
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
1行だけの docstring なら、全部同じ行に置いてください:
"""Return an ex-parrot."""
Naming Conventions(命名規則 )
Python の命名規則 はすこしの混乱がある (a bit of a mess) ため、命名規則 に完全な一貫性を取ることはできないでしょう。しかしながら、現在の推奨される命名 標準 (naming standards) を以下に示します。
新しい module や package(third-party の framework を含む)は、示す命名 標準に従って書かれるべきですが、既存のライブラリが(すでに)異なる style を持っているときは、内部的な一貫性を優先すべきです。
Overriding Principle(他よりも優先される原則)
API の公開部分としてユーザーに見える(見られる)名前は、実装ではなくて用途に即した命名規則 に従うべきです。
def calculate_checksum (): ...
def hash_md5_internal_func (): ...
Descriptive: Naming Styles(叙述 or 説明的な命名 の style)
naming style には、いろいろなものがある。その名前が何に使われているのかとは関係なく、どのような naming style が使われているのかを認識することは役に立ちます。
一般的には、以下のような naming style が区別されて存在している:
b(1文字だけの小文字)
B(1文字だけの大文字)
lowercase
lower_case_with_underscores
UPPERCASE
UPPER_CASE_WITH_UNDERSCORES
CapitalizedWords(CapWords, CamelCase, StudlyCaps とも言う。文字が凸凹している見た目からついた名前)
Note: CapWords で 頭字語 (acronym) を使うときは、頭字語のすべての文字を大文字にします。(なので HttpServerError よりも HTTPServerError がよい)
mixedCase (CapitalizedWords との違いは最初の文字が小文字)
Capitalized_Words_With_Underscores(醜い)
また、関連する名前をグループ化するために、短い unique prefix を使用する style もあります。これは python では、あまり使われませんが、念のため記載しておきます。
例えば、os.stat()
関数は、伝統的に st_mode, st_size, st_mtime などの名前を持った tuple を返却します。(これは POSIX system call 構造体の field との対応を強調するためのもので POSIX system call 構造体に慣れているプログラマ にとって、役に立つ名前になります)
(一例ですが、UNIX 系 OS で広く使われている)X11 ライブラリでは、すべての public 関数の頭に "X" をつけています。python では、この style は一般的に不要だと考えられています。なぜなら、attribute と method の名前の前には object が付き、function の名前の前には module の名前が付くからです。(それぞれ object と module が prefix として利用される)
加えて、先頭/末尾の underscore を使用する以下の特殊な形式が認識されています(これらは、一般的にどのような規則とも組み合わせることができる):
_single_leading_underscore
弱い内部使用 “internal use” の indicator(標識)です。
例:from M import *
では underscore の付く名前は import されません。(=なので内部使用である)
single_trailing_underscore_
python のキーワードとの衝突を避けるために使用されます。
例:tkinter.Toplevel(master, class_='ClassName')
__double_leading_underscore
class attribute の命名 に使用すると名前の mangling が発生します。
例:__boo
は FooBar
クラスの中では _FooBar__boo
になる。
double_leading_and_trailing_underscore
ユーザー制御の名前空間 に存在する "masic" object or attribute の名前。
例:__init__
, __import__
, __file__
のような名前は決して使ってはいけないです。(公式に)ドキュメントにある名前のものだけを利用すること。(=なので勝手に独自の dunder を定義してはいけない)
Prescriptive: Naming Conventions(模範的な命名規則 )
Names to Avoid(避ける名前)
小文字の l
(エル)大文字の O
(オー), I
(アイ)を1文字の変数名として使用しないこと。font によっては、これらの文字は見分けがつかなくなります。どうしても l
を使いたいときは L
を使ってください。
ASCII Compatibility(ASCII 互換性)
標準ライブラリで使用される識別子は、PEP3131 の policy の section に記述されているように ASCII 互換でなければならない。
つまり、変数名や関数名は英数字 (ASCII) の文字のみを使うこと。
def データを取得する():
return "data"
π = 3.14
Package and Module Names(package と module の名前)
module の名前は短くして、すべて小文字 (all-lowercase) にすること。読みやすくなるのであれば、underscore を使ってもよいです。python package も underscore の使用は推奨されません。しかしながら、すべて小文字 all-lowercase の短い名前を持つべきです。
C or C++ の拡張 module で、より高レベルの(例:more オブジェクト指向 な)interface を提供する python module が付属しているときは、C/C++ module には underscore が付きます。(例:_socket
)
import _socket
import socket
Class Names
class の名前は CapWords 記法を使うべきです。
class MyClass :
pass
class UserProfile :
pass
class を function のように使用することが document 化されていて、実際にも主に関数のように呼び出して使う (callable) 場合は、function の命名規則 を class の規則の代わりに使ってもよいです。
class make_widget :
def __call__ (self, name):
return f"widget: {name}"
w = make_widget()
w("button" )
Note: builtin の名前には別の規則があることに注意すること:多くの builtin の名前は単語1~2語です。CapWords が使われるのは exception や builtin 定数の名前のみです。
種類
命名 style
例
builtin 関数
小文字1~2語
len, open, isinstance
builtin 例外
CapWords
ValueError, TypeError
builtin 定数
CapWords
None, True, False
Type Variable Names(型変数の名前)
PEP484 で導入された type variable は CapWords を使用して、短い名前を好みます。(例:T
, AnyStr
, Num
)
convariant or contravariant の振る舞いを宣言する type variable の使い方では、それぞれ _co
や _contra
の suffix をつけることを推奨します。
from typing import TypeVar
VT_co = TypeVar('VT_co' , covariant=True )
KT_contra = TypeVar('KT_contra' , contravariant=True )
convariant のサンプルは、以下:
from typing import TypeVar, Generic
class Animal :
def speak (self):
print ("I'm an animal." )
class Dog (Animal):
def speak (self):
print ("Woof!" )
T_co = TypeVar('T_co' , covariant=True )
class Box (Generic[T_co]):
def __init__ (self, value: T_co):
self.value = value
def get (self) -> T_co:
return self.value
dog_box = Box(Dog())
animal_box: Box[Animal] = dog_box
animal_box.get().speak()
Exception Names
exception は class であるべきなので、class の命名規則 が適用されます。ただし、(もしも、実際に "Error" なら)exception の名前には "Error" という語尾を付けるべきです。
C# だと語尾にほぼすべて ~Exception
のような名前になっています。python では語尾に Error を付けないことがあるということ。たとえば C# の OperationCanceledException
に相当する例外は raise KeyboardInterrupt
なので、例外処理なんだけど、異常のようには(いくらか)見えづらい。たしかに C# の例外は「悪」に見えるのかもしれないと思ったが、例外は「本当に例外的なことが起きたとき」に使うものという思想があるはず。
python だと raise ~
の形を制御 flow にも使う柔軟な考え方になっていると思う。だけど、どちらもパフォーマンス面ではコストが高いので仕様を理解して柔軟に利用すること。
Global Variable Names(グローバル変数 の名前)
(※グローバル変数 は、ひとつの module の中でだけで利用するようにします)命名規則 は、function と同じです。
from M import *
の使い方を想定して設計された module は、グローバル変数 の export を防ぐために __all__
のメカニ ズムを使うべきです。また、従来の方法である underscore を(名前の最初に)付けることで non-public を示す方法も使えます。
__all__ = ['func1' ]
def func1 ():
pass
def func2 ():
pass
_my_global = 42
from module_a import *
Function and Variable Names
function の名前は、小文字 lowercase で書きます。読みやすくするため、必要に応じて underscore で区切ってください。
変数 variable の名前も同じ規則に従います。
mixedCase は、すでにその style が使われるようなケース(例:threading.py)に限ってください。後方互換 性を保つために認められます。
Function and Method Arguments
instance method の第一引数は、常に self
を使うこと。
class method の第一引数は、常に cls
を使うこと。
もしも function の引数名が予約語 と衝突するなら、一般的には省略したような語や崩れた語 spelling corruption を使用するよりも末尾に underscore をひとつ追加したほうがよい。
def foo (class_):
pass
def foo (clss):
pass
したがって、 class_
のほうが clss
よりも優れています。(同義語 synonym を使用することで、このような衝突を避けることができるかも)
Method Names and Instance Variables(メソッド名とインスタンス 変数)
function の命名規則 :読みやすくするために、必要に応じて underscore で単語を区切った小文字を使うこと。
underscore を(名前の最初に)ひとつ使用するのは non-public method と instance 変数のみです。
subclass との衝突を避けるために python の mangling ルールを使用してください。(名前の最初に __
のように underscore を2つ付ける)
python はこれらの名前を class の名前を使いつつ「名前の書き換え」name mangling をします:もし Foo クラスに __a
という名前の attribute があっても Foo.__a
ではアクセスできません。(しつこいユーザーは Foo.Foo__a
の記述でアクセスできるけど)
一般的に、二重の underscore は、subclass 化をする class の属性と名前の衝突を避けるためだけに使用するべきです。
Note: __names
の使用については、議論が存在します。(後述のとおり)
ここでの mangling は名前を「変形して隠すこと」です。subclass にも使ってほしくないということにもなります。具体的には underscore の部分が該当していて、内部的には Foo.Foo__a
の部分で衝突を防ぐ。
class Base :
def __init__ (self):
self.__data = 123
class Sub (Base):
def __init__ (self):
super ().__init__()
self.__data = 999
b = Sub()
print (dir (b))
Constants(定数)
定数 constant は、通常だと module のレベルで定義されます。すべて大文字で書き、単語の区切りは underscore を使います。
例:MAX_OVERFLOW
, TOTAL
など
Designing for Inheritance(継承のための設計)
class の method や instance 変数の(総称:属性 attribute)を public or non-public にするべきかを、常に(あらかじめ)決めておくこと。public を後から non-public に変更するよりも、後から public に変更するほうが簡単です。
public attribute は、あなたの class を関係のない(外部の)client が使用することを期待しています。なので、後方互換 性のない変更を避ける(維持を約束する)ものです。
non-public attribute は、(第三者 )third-party が利用することを意図しないことを示す attribute です。逆に non-public 属性のものは、変更や削除の保証をしていません。
ここでは "private" という用語は使いません。python は本当の意味での private attribute は存在していません。(実現するには、不必要なたくさんの処理が必要になるから)
もうひとつの attribute の category として "subclass API " があります。(他の言語では、よく "protected" と呼ばれます)
class の中には継承されることを前提に設計されているものがあります。この class の動作の拡張/変更のために subclass を使うことが想定している attribute です。
どれが public attribute にするのか、どれが subclass API で、どれが基底 class だけで使う non-public なのかを、明確に決定するように注意しましょう。
ここまでの内容を踏まえて、(python 的な)pythonic なガイドライン を示します:
public attribute には、頭に underscore をつけるべきではありません。
もしも、public attribute の名前が予約語 と衝突するときは、属性名の末尾に underscore をひとつ追加します。これは、省略や間違ったスペル corrupted spelling よりも望ましいです。(しかしながら、この規則に関わらず、class であることがわかっている変数や引数、特に class method の最初の引数には cls
が例外的に好まれる)
Note 1: class method については、前述のルールを参照すること。
単純な public データの attribute では、複雑な accessor/mutator method を使わずに、attribute の名前だけを公開することがベストです。単純なデータの attribute が(後から)機能的な振る舞いを成長させる必要があることに気づいたとしても、python は将来的な機能拡張の簡単な方法を提供している、と心に留めておくこと。そのようなケースでは、property を使用して、単純なデータ attribute の access 構文のあとに機能的な実装を隠します。
Note 1: 機能的な振る舞いには、副作用 side-effect のないように保ちます。ただし、cache などは一般的に問題ありません。
Note 2: 計算量の多い処理には proprty を使うことを避けること。attribute の表現は、呼び出す側も access が(比較的)軽い処理だと信じています。
もしも、class は subclass 化されることを想定していたとします。subclass には使わせたくない attribute があるときは、頭に underscore を2つ付けた名前を検討してください。(ただし、末尾にも underscore を2つ付けると __a__
になるから駄目で __a
にする)この名前は name mangling の algorithm の機能を呼び出します。subclass が同じ名前の attribute を持つときは、attribute の衝突を回避できます。
Note 1: name mangling は、単純に class の名前が(attribute の名前に対して追加で)埋め込まれるだけなので、subclass がまったく同じ class の名前と attribute の名前を持つと衝突します。
Note 2: name mangling は debug や __getattr__()
を使いたいようなときに、不便になっている恐れがある。しかしながら、name mangling の algorithm はよく document 化されているので manual で実行することも簡単です。
Note 3: name mangling を誰もが好むわけではありません。名前の衝突を回避する(本当のところの)必要性と、高度な使い方になることとのバランスを考慮すること。
Public and Internal Interfaces(公開型 interface と内部型 interface)
後方互換 性の保証(の必要性)は、public interface にのみ適用されます。したがって、ユーザーは public interface と internal interface を明確に区別できるようにすることは大切です。
文書化された interface は、文書で明示的に「暫定的 provisional」or「内部型 internal」とされていない限り、(デフォルトで)public interface だと、みなされます。また、文書化されていない interface は、すべて internal interface だとみなされるべきです。
introspection をより良い形で support するために module は __all__
attribute を使用して、public API の名前を明示的に宣言する必要があります。
introspection とは、実行中の object の情報をプログラムの中から調べること。C# だと Reflection が近い。たとえば type()
は object の型を取得し、dir()
は利用可能な attribute, method を一覧にします。
__all__ = []
を空っぽのリストに設定することは、その module には public API が存在しないことを示します。
__all__
を適切に設定していても、internal interface(package, module, class, function, attribute, その他の名前)には、先頭に underscore の prefiex をひとつ付けて名前をつけるべきです。
もしも、ある名前空間 に存在する package, module, class が internal なものであるなら、その中に存在するinterface もまた internal であるとみなされます。
import した名前は、常に実装の詳細である、とみなされるべきです。他の module は os.path
や __init__
のように文書化されている場合を除いて、それらの名前を間接的に参照するべきではありません。
他の module から import した名前 (function, class) などは、基本的にその module の内部実装です。なので public API 以外は使うな、依存するなという話をしているだけだと思う。
Programming Recommendations(プログラミングの推奨事項)
code は、他の python の実装 (PyPy, Jython , IronPython , Cython, Psyco, ...) の不利益にならない書き方をするべきです。
例えば a += b
や a = a + b
のような形式で書かれる statement、(in-place) string の連結において、CPython の効率的な実装に頼ってはいけないです。この最適化は CPython でも不安定(いくつかの型にしか効果がない)で、参照カウント refcounting を使わない他の実装では、(最適化は)まったく存在していません。ライブラリの performance に敏感な部分では、代わりに ''.join()
を使うべきです。これによって、さまざまな実装において、連結処理が線形時間で行われるようになります。
def good_concat (words):
return '' .join(words)
print (good_concat(["a" ] * 10000 ))
def bad_concat (words):
result = ""
for word in words:
result += word
return result
print (bad_concat(["a" ] * 10000 ))
最初に文字列の長さを計算して buffer を1回で確保してから一括で連結するようなこと。
None のような singleton との比較は is
か is not
を使うこと。==
や !=
のような等値演算子 equality operator は使わないこと。
また、もしも if x is not None
のつもりのとき if x
と書いているなら注意してください。例えば、default の値が None に設定されている変数や引数に対して、なにか別の値が設定されているかどうかをテストするケースがあります。ここの他の値は boolean 型の文脈 context では false と評価される型(例えば container など)かもしれません。
not ... is
よりも is not
演算子 を使うこと。どちらの表現も機能的には同じですが is not
のほうが読みやすい。
if foo is not None :
if not foo is None :
拡張比較 rich comparison による order 操作を実装するとき、他 code が特定の比較しか使わないと期待するのではなくて、6つすべての演算子 を実装することが best です。
__eq__
, __ne__
, __lt__
, __le__
, __gt__
, __ge__
(実装に)必要な手間を最小にするために functools.total_ordering()
decorator は、附則している比較 method を(自動で)生成する tool を提供します。
PEP 207 によると python では(比較において)反射性 reflexivity のルールを前提としています。よって、interpreter は y > x
と x < y
に入れ替えたり Y >= x
と x <= y
を入れ替えたり X == y
と x != y
の引数を入れ替えたりすることがあります。
sort()
と min()
演算子 は <
演算子 を使って max()
演算子 は >
を使って動作することが保証されています。
しかし、他の文脈 context において混乱が生じないように(繰り返しになっているけど)6つの演算子 をすべて実装しておくことが best です。
class Item :
def __lt__ (self, other):
return self.value < other.value
max ([Item(), Item()])
lambda 式を識別子に直接 bind する代入文 assignment statement の代わりに、常に def
statement を使うこと。
最初の形式 def
は、生成される function object の名前が明示的に f
になりますが lambda を使うと、名前は lambda
という汎用的な名前になることを意味します。
このやり方 def
のほうが traceback(エラー表示)や、文字列表現の全般において有利です。代入文 assignment statement を使うと lambda 式が提供できる唯一の利点(おおきな式に対して埋め込めること)を失ってしまいます。
def f (x): return 2 *x
f = lambda x: 2 *x
exception chaining を適切に使うこと。raise X from Y
は、もとの traceback を失うことなく、明示的に(例外を)置き換える意図を示すために使用するべきです。
inner exception を意図的に置き換えるとき(raise X from None
を使う)、新しい exception に関連する詳細を伝えるようにします。
(KeyError を AttributeError に変換するとき、attribute name を保持したり、もとの exception の text を埋め込む、など)
try :
int ("abc" )
except ValueError as e:
raise RuntimeError ("入力の変換に失敗しました" ) from e
exception を catch するときは、(指定のない)except:
を使う代わりに、可能な限り特定された exception を指定すること:
(指定のない)except は、 SystemExit と KeyboardInterrupt のような例外も catch してしまいます。なので Ctrl+C
によるプログラムの中断を難しくしてしまいます。もしも、program の error を示したすべての exception を catch したいなら except Exception:
を使います。ちなみに(指定のない)except は except BaseException:
と同義です。
経験則として、(指定のない)except の使用は2つのケースに限定するとよいと思います。
traceback(エラー内容)を出力 or ログに記録するとき。すくなくとも、ユーザーはerror が発生したことを認識できます。
もしも code がなんらかの cleanup の作業をする必要があるが、raise でexception を(上方 upward に)伝播させてしまうとき。このケースは try...finally
のほうが良い方法になるかも。
try :
import platform_specific_module
except ImportError :
platform_specific_module = None
operationg system の error を catch するときは errno の値から判定 introspection するよりも、python 3.3 で導入された明示的な exception 階層を使うと良いです。
import errno
try :
open ("no_such_file.txt" )
except OSError as e:
if e.errno == errno.ENOENT:
print ("ファイルが見つからない" )
try :
open ("no_such_file.txt" )
except FileNotFoundError :
print ("ファイルが見つからない" )
すべての try/except
節において try
節は、最低限の code に制限してください。これは bug の隠蔽を避けるためです:
try :
value = collection[key]
except KeyError :
return key_not_found(key)
else :
return handle_value(value)
try :
return handle_value(collection[key])
except KeyError :
return key_not_found(key)rrno values.
resource が code の特定の section に局所的に存在するときは with
statement を使用して、使用後に確実かつ速やかに cleanup されるようにします。
try/finally statement も同様のことができます。
with open ("data.txt" , "r" ) as f:
data = f.read()
f = open ("data.txt" , "r" )
try :
data = f.read()
finally :
f.close()
context manager は、resource の獲得 or 解放以外のことをするなら、別の function or method を通して呼び出されるべきです。
後者の例 with conn:
では __enter__
method と __exit__
method が transaction の接続を閉じる以外に、なにをするのか情報が何もない。(なにをするのか)明示的に示すことが重要です。
with conn.begin_transaction():
do_stuff_in_transaction(conn)
with conn:
do_stuff_in_transaction(conn)
with は明確な resource 操作をしたい。なので with の意図を明確にしておく。なので function/method を通すと function/method の名前で意図を示すことができる。
return statement には、一貫性を持たせること。fuction の return statement は(値や式を)すべて返却するか、すべて何も返却しないか、のどちらかにしなければいけません。
もしも return statement が、式 expression を返却するなら、値を返さない return のところは return None を書きます。明示的な return statement は function の最後に提供されるべきです。(その位置に到達できるなら)
def foo (x):
if x >= 0 :
return math.sqrt(x)
else :
return None
def bar (x):
if x < 0 :
return None
return math.sqrt(x)
def foo (x):
if x >= 0 :
return math.sqrt(x)
def bar (x):
if x < 0 :
return
return math.sqrt(x)
prefix や suffix を確認するときは文字列の slice の代わりに ''.startswith()
と ''.endswith()
を使うこと。コードがすっきりしていて error も起こりにくいです:
if foo.startswith('bar' ):
if foo[:3 ] == 'bar' :
object の型比較は、型を直接比較するのではなくて、常に isinstance()
を使うべきである:
if isinstance (obj, int ):
if type (obj) is type (1 ):
sequence (string, list, tuple) については、空っぽの sequence は false であるという(python の)特性を利用すること:
if not seq:
if seq:
if len (seq):
if not len (seq):
空の list かどうかを調べるために len(seq) == 0
を書かないってことだと思う。
末尾の空白 whitespace に依存した文字列 literal は書かないこと。このような(末尾の)空白は視覚的に判断できないし、editor によっては(最近だと eindent.py
) trim してしまう。
text = "ユーザー名: "
input (text)
bool 値を true
or false
と比較するために ==
を使わないこと:
if greeting:
if not greeting:
if greeting == True :
if greeting is True :
try...finally
の finally
suite の中で return/break/continue といったフロー制御文 flow control statement を使用することは推奨されません。なぜなら、このような statement は finally suite を伝搬している active な exception を暗黙のうちに cancel してしまうからです:
def foo ():
try :
1 / 0
finally :
return 42
Function Annotations
PEP 484 が採用されたことで、function annotation の style rule は変更されました。
function annotation は PEP 484 の構文を使うべきです。(前の section に annotation については、いくつかの推奨があります)
PEP 8(の過去のもの)で以前に推奨していた annotation style(の実験版)はもう推奨されていません。
しかしながら、標準ライブラリ以外では、PEP 484 のルールの範囲内での実験的使用は推奨されています。例えば、大規模な third-party のライブラリや application を PEP 484 style の型 annotation で markup して、それらの annotation を追加する難しさを review して、それらの存在によって code の理解のしやすさを向上するのかどうかを観察するといったことです。
python の標準ライブラリはこのような annotation の採用には慎重(保守的)であるべきですが、新しい code や大きな refactoring では、その使用を認めています。
function annotation を別の形で使いたい code には、以下のような comment を付けることを推奨します:
# type: ignore
# 型検査を無効化する
(ファイルの先頭近くに書くことで)これは type checker がすべての annotation を無視するように指示します。(より細かい制御の方法は PEP 484 を参照すること)
linter と同様に type checker は、optional な外部の tool です。python の interpreter は type check による message を発行させないこと。annotation に基づいて振る舞いを変更するべきではありません。
type checker を使いたくないユーザーは、自由にそれを無視できます。しかしながら、third-party のライブラリを使うユーザーは、package で type checker を実行したいと思うかもしれません。この目的のために PEP 484 は stub file .pyi
の使用を推奨しています。.pyi
file は対応する .py
file の代わりに type checker によって読み込まれます。stub file はライブラリと一緒に配布することもできるし(ライブラリ作者の許可のもと)typeshed repo を通じて個別に配布することもできます。
Variable Annotations
PEP 526 では variable annotation が追加されました。variable annotation の推奨 style は、前述の function annotation と同じです:
module レベルの変数、class 変数、instance 変数、local 変数の annotation は colon :
の後に半角 space をひとつ入れるべきです。
colon の前後に space を入れるべきではありません。
もしも、代入に右辺があるなら、等号の両辺にはひとつずつの space を入れるべきです。
code: int
class Point :
coords: Tuple[int , int ]
label: str = '<unknown>'
# Wrong:
code:int # colon の後に space がない
code : int # colon の前に space がある
class Test:
result: int=0 # '=' の前後に space がない
PEP 526 は python 3.6 から採用されていますが、この variable annotation は、すべての python 向けの stub file .pyi
でも推奨される構文です。(詳しくは PEP 484 を参照)
参考