- Introduction(はじめに)
- A Foolish Consistency is the Hobgoblin of Little Minds(愚かな一貫性は小さな心のホブゴブリン)
- Code Lay-out
- String Quotes(文字列の quote 処理)
- Whitespace in Expressions and Statements(expression や statement における空白)
- When to Use Trailing Commas(末尾カンマを使うとき)
- Comments
- Naming Conventions(命名規則)
- Overriding Principle(他よりも優先される原則)
- Descriptive: Naming Styles(叙述 or 説明的な命名の style)
- Prescriptive: Naming Conventions(模範的な命名規則)
- Names to Avoid(避ける名前)
- ASCII Compatibility(ASCII 互換性)
- Package and Module Names(package と module の名前)
- Class Names
- Type Variable Names(型変数の名前)
- Exception Names
- Global Variable Names(グローバル変数の名前)
- Function and Variable Names
- Function and Method Arguments
- Method Names and Instance Variables(メソッド名とインスタンス変数)
- Constants(定数)
- Designing for Inheritance(継承のための設計)
- Public and Internal Interfaces(公開型 interface と内部型 interface)
- Programming Recommendations(プログラミングの推奨事項)
- 参考
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 のことを指します。
# Correct: # 垂直にそろえている foo = long_function_name(var_one, var_two, var_three, var_four) # ぶら下がりインデント:4-space 分だけ字下げ def long_function_name( var_one, var_two, var_three, var_four): print(var_one) # 呼び出しのときも、ぶら下がりインデントで OK foo = long_function_name( var_one, var_two, var_three, var_four)
# Wrong: # ぶら下がりインデントなのに引数を1行目に入れてるから NG foo = long_function_name(var_one, var_two, var_three, var_four) # 継続する行のインデントが浅くてわかりづらいから NG # 本当は 4-space のインデントがあったほうがいい def long_function_name( var_one, var_two, var_three, var_four): print(var_one)
継続行における 4-space のルールは必須ではありません。
任意の例:
# ぶら下がりインデントは4つ以外も可能な例
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): # Since both conditions are true, we can frobnicate. 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())
# python 3.10 以降ではそもそも問題ない with ( open("file1") as f1, open("file2") as f2 ):
(このような複数行の with
statement の indent については、複数行の if
statement に関する話を参考にすること)
もうひとつのケースは assert
statement です。続きの行を適切に indent してください。
(以下は勝手に追記している)おそらく:
# Correct: 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"
# Wrong: assert some_long_condition and another_condition # どこまでが条件か不明瞭
Should a Line Break Before or After a Binary Operator?(binary operator の前後で改行すべきか?)
何十年もの間 binary operator の後で改行することが推奨されていました。しかし、演算子は画面上の異なる位置に散らばる傾向があり、各演算子は operand から離れて前の行に移動しています。
なので、どの項目が加算されて、どの項目が減算されたのかを見分けるためには、目は面倒な動作をすることになる。
# Wrong: # 演算子は operands から離れているパターン income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest)
この読みやすさの問題を解決するために、数学者と出版社は反対の慣例に従っています。Donald Knuth は彼の Computers and Typesetting シリーズでルールを説明しています:"段落内の(インライン)数式は binary operator の後で改行され、ブロック形式の (displayed) 数式 は operator の前で改行される"(Tex の話)
数学の伝統に従うことで、通常は読みやすいコードになります:
# Correct: # 演算子と operand のマッチングが簡単 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 は通常、別の行にすべきです:
# Correct: import os import sys
# Wrong: import sys, os
とは言っても、このようにしても OK です(同じモジュールから複数の機能を import する例):
# Correct: from subprocess import Popen, PIPE
import は必ずファイルの一番最初に書かれます。モジュールに対する comment や docstring のすぐ後であり、module の globals や constaints の前です。
# モジュールに関するコメント(任意) # This module handles user authentication management. # import 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 *
が役に立つことがあります)
# C拡張モジュール(高速化)を使えたらそれを優先して取り込む try: from ._accelerator import * except ImportError: from ._fallback import *
このように名前を再公開するときも、public & internal interface の扱いに関する guideline は以前として適用されます。
Module Level Dunder Names(モジュールレベルの dunder の名前)
dunder name とは、名前の先頭と末尾に underscore を2つずつ持つ __name__
のような特別な名前のことです。これをどこに書くべきか、ということです。dunder = double underscore のこと。口語的なスラングでダンダーが近い発音になる。
例えば __all__, __author__, __version__
などはモジュールの docstring の直後に挿入し import の前に配置するべきです。__future__
からの import は例外で、python は docstring を除いて、コードの一番最初に future-import が現れることが義務付けられています。
# PEP257 形式の docstrings """This is the example module. This module does stuff. """ # future インポート(使う場合は、一番最初に書く) from __future__ import barry_as_FLUFL # dunder を定義 __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 を使います。このほうが読みやすいからです。
# Correct: quote = "I'm happy." # single-quote があるから double-quote quote = 'He said, "Hi."' # double-quote があるから single-quote
# Wrong: 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 を避けること:
# Correct: spam(ham[1], {eggs: 2})
# Wrong: spam( ham[ 1 ], { eggs: 2 } )
末尾のカンマ ,
と括弧の間も、余計な余白の space を避けること:
# Correct: foo = (0,)
# Wrong: bar = (0, )
カンマ ,
、セミコロン ,
、コロン :
の直前も、余計な余白の space を避けること:
# Correct: if x == 4: print(x, y); x, y = y, x
# Wrong: 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:]
は、空白も省略。
# Correct: 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]
# Wrong: ham[lower + offset:upper + offset] ham[1: 9], ham[1 :9], ham[1:9 :3] ham[lower : : step] ham[ : upper]
関数の引数リストを開始する括弧の直前は、余計な space を避けること:
# Correct: spam(1)
# Wrong: spam (1)
indexing や slicing の括弧 []
の前は、余計な space を避けること:
# Correct: dct['key'] = lst[index]
# Wrong: dct ['key'] = lst [index]
代入演算子 =
の前後は、(他行の演算子と整列させるために)空白を入れすぎないこと:
# Correct: x = 1 y = 2 long_variable = 3
# Wrong: 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個)を入れること。
# Correct: i = i + 1 submitted += 1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b)
# Wrong: 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」を参照)
# Correct: def munge(input: AnyStr): ... def munge() -> PosInt: ...
# Wrong: def munge(input:AnyStr): ... def munge()->PosInt: ...
キーワード引数を示す場合や、annotation のない関数パラメータにデフォルト値を指定するときは =
の前後に空白を入れないこと:
# Correct: def complex(real, imag=0.0): return magic(r=real, i=imag)
# Wrong: def complex(real, imag = 0.0): return magic(r = real, i = imag)
ただし、引数 annotation とデフォルト値を組み合わせるときは =
の前後に空白を使用すること:
# Correct: def munge(sep: AnyStr = None): ... def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
# Wrong: def munge(input: AnyStr=None): ... def munge(input: AnyStr, limit = 1000): ...
複合 statement(同じ行に複数の statement を書くこと)は、一般的に推奨されません:
# Correct: if foo == 'blah': do_blah_thing() do_one() do_two() do_three()
# Wrong (Rather not = しないほうがいいと思う): if foo == 'blah': do_blah_thing() do_one(); do_two(); do_three()
if, for, while を同じ行に書いてもいいことがあります。しかし、複数の節 multi-clause を持つコードのところでは、するべきではないです。また、長いコードを無理に折り返すことも避けること!
# Wrong (Rather not = しないほうがいいと思う): if foo == 'blah': do_blah_thing() for x in lst: total += x while t < 10: t = delay()
# Wrong (Definitely not = 絶対に違う): 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 を除く)
# Correct: FILES = [ 'setup.cfg', 'tox.ini', ] initialize(FILES, error=True, )
# Wrong: FILES = ['setup.cfg', 'tox.ini',] initialize(FILES, error=True,)
tuple のような場合は ('tox.ini',) にしないと tuple にならない。 ('tox.ini') では値になる。
Comments
コードと矛盾するコメントは、コメントが無いことよりも悪いものです。コードが変更された時は、常にコメントを最新の状態に保つことを優先すること!
コメントは完全な文章でなければならないです。最初の文字は大文字で始めます。(識別子の大文字小文字は、絶対に変えないこと!)
block comment は、通常だと完全な文章をひとつ以上の段落で構成します。それぞれの文はピリオドで終わるようにします。
複数の文で構成されるコメントでは、文の末尾のピリオドの後に1 or 2の空白を使用する必要があります。
英語を母国語としない国の python corder のコメント:そのコードがあなたの言語を母国語としない人に読まれることは絶対にないことを 120% 確信していない限り、コメントは英語で書いてください。
最後の指摘は
unless
xnever be read
xby people who don't speak your language
で否定が3つもある文章構造。単に「英語以外で書くな」と示すと言葉として強すぎるので、とても強く制限をかけたい言い回しになっている。120%の確信なんてありえないから、英語で書いてねと読んでおけばいい気がする。(もしくは、あなただけのプライベートなコードなら好きにしたらいい、とも読める)
Block Comments
block comment は一般的に、それに続くコードの一部、または、すべてに適用されます。そして、(コメントを挿入する位置の)コードと同じ位置(レベル)にインデントします。
block comment の各行は #
と、ひとつの space #
から始まります。(コメント内のテキストが、引用、サンプルコードなどの理由で特別なインデントのある場合は別)
block comment 内の段落は "#" だけの1行で区切る。
# This function initializes the database connection # and prepares the schema if necessary. # # It should be called once at the beginning of the program, # before any database access occurs.
Inline Comments
inline comment は控えめに使うこと。
inline comment とは、statement と同じ行にあるコメントのことです。inline comment は statement から少なくとも2つの space で区切らなければいけません。inline comment は
#
で始めてください。
(コードの内容が)明らかなことを述べるのであれば inline comment は邪魔になります。以下のようなものは書かないこと:
# コードを見れば明らかなことは書かないこと x = x + 1 # Increment x
しかし、役に立つ inline comment もある:
# なぜ加算をしているのかを説明している(コード理解の補足) x = x + 1 # Compensate for border
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. """ # ↑ docstring の末尾は `"""` 以外になにも書かない
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 の公開部分としてユーザーに見える(見られる)名前は、実装ではなくて用途に即した命名規則に従うべきです。
# Correct: 使う側の目的に沿った名前 def calculate_checksum(): ... # Wrong: 実装の都合に合わせた名前 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
- 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) の文字のみを使うこと。
# Wrong # 日本語の関数の名前 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
)
# C/C++ の拡張 module import _socket # python の module 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 # Box[Dog] は Box[Animal] として扱える(共変) dog_box = Box(Dog()) animal_box: Box[Animal] = dog_box # 確認 animal_box.get().speak() # Woof!
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 を示す方法も使えます。
# module_a.py __all__ = ['func1'] # これで func1 以外は * でインポートされない def func1(): pass def func2(): pass _my_global = 42
from module_a import * # func1 は使えるが、func2 や _my_global はインポートされない
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 をひとつ追加したほうがよい。
# Correct def foo(class_): # class_ は一目で意図がわかる pass
# Wrong def foo(clss): # 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 # Base の __data class Sub(Base): def __init__(self): super().__init__() self.__data = 999 # Sub の __data b = Sub() print(dir(b)) # _Base__data と _Sub__data がある
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()
を使うべきです。これによって、さまざまな実装において、連結処理が線形時間で行われるようになります。
- 例えば
# Correct def good_concat(words): return ''.join(words) print(good_concat(["a"] * 10000))
# Wrong 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
のほうが読みやすい。
# Correct: if foo is not None:
# Wrong: 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
の引数を入れ替えたりすることがあります。 - しかし、他の文脈 context において混乱が生じないように(繰り返しになっているけど)6つの演算子をすべて実装しておくことが best です。
# Wrong class Item: def __lt__(self, other): # < 定義 return self.value < other.value # max() を使うと __gt__ が呼ばれるので ERROR max([Item(), Item()])
- lambda 式を識別子に直接 bind する代入文 assignment statement の代わりに、常に
def
statement を使うこと。- 最初の形式
def
は、生成される function object の名前が明示的にf
になりますが lambda を使うと、名前はlambda
という汎用的な名前になることを意味します。 - このやり方
def
のほうが traceback(エラー表示)や、文字列表現の全般において有利です。代入文 assignment statement を使うと lambda 式が提供できる唯一の利点(おおきな式に対して埋め込めること)を失ってしまいます。
- 最初の形式
# Correct: def f(x): return 2*x
# Wrong: 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 を埋め込む、など)
- inner exception を意図的に置き換えるとき(
try: int("abc") except ValueError as e: # RuntimeError への置き換えをするが 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
のほうが良い方法になるかも。
- (指定のない)except は、 SystemExit と KeyboardInterrupt のような例外も catch してしまいます。なので
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 の隠蔽を避けるためです:
# Correct: try: value = collection[key] except KeyError: return key_not_found(key) else: return handle_value(value)
try: # 範囲が広すぎる return handle_value(collection[key]) except KeyError: # handle_value() が発生させた KeyError も catch してしまう 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.close() が呼ばれる
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 の接続を閉じる以外に、なにをするのか情報が何もない。(なにをするのか)明示的に示すことが重要です。
- 後者の例
# Correct: with conn.begin_transaction(): do_stuff_in_transaction(conn)
# Wrong: 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 の最後に提供されるべきです。(その位置に到達できるなら)
# Correct: 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)
# Wrong: def foo(x): if x >= 0: return math.sqrt(x) # return がない def bar(x): if x < 0: return # 値がない return math.sqrt(x)
- prefix や suffix を確認するときは文字列の slice の代わりに
''.startswith()
と''.endswith()
を使うこと。コードがすっきりしていて error も起こりにくいです:
# Correct: if foo.startswith('bar'):
# Wrong: if foo[:3] == 'bar':
- object の型比較は、型を直接比較するのではなくて、常に
isinstance()
を使うべきである:
# Correct: if isinstance(obj, int):
# Wrong: if type(obj) is type(1):
- sequence (string, list, tuple) については、空っぽの sequence は false であるという(python の)特性を利用すること:
# Correct: if not seq: if seq:
# Wrong: if len(seq): if not len(seq):
空の list かどうかを調べるために
len(seq) == 0
を書かないってことだと思う。
- 末尾の空白 whitespace に依存した文字列 literal は書かないこと。このような(末尾の)空白は視覚的に判断できないし、editor によっては(最近だと
eindent.py
) trim してしまう。
# Wrong: text = "ユーザー名: " # 末尾に空白がひとつある(でも見えない) input(text)
- bool 値を
true
orfalse
と比較するために==
を使わないこと:
# Correct: if greeting: if not greeting:
# Wrong: if greeting == True: # Wrong(Worse): if greeting is True:
try...finally
のfinally
suite の中で return/break/continue といったフロー制御文 flow control statement を使用することは推奨されません。なぜなら、このような statement は finally suite を伝搬している active な exception を暗黙のうちに cancel してしまうからです:
# Wrong: def foo(): try: 1 / 0 # ZeroDivisionError が発生 finally: return 42 # return により exception を無視
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 を入れるべきです。
# Correct: 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 を参照)