Source

pyguide-ja / pyguide.rst

Google Python スタイルガイド

概要

これは Google Python Style Guide Revision 2.29 を日本語に訳したものです。

本家ガイドは CC-By 3.0 ライセンス の基で公開されています。また、本ガイドも同ライセンスを継承します。

本家ガイドの著者は以下の通りです。

  • Amit Patel
  • Antoine Picard
  • Eugene Jhong
  • Jeremy Hylton
  • Matt Smart
  • Mike Shields

また、本ガイドの翻訳者は以下の通りです。

  • Kosei Kitahara

本ガイドに誤植、誤訳があった場合は issue で教えてください。 その他本ガイドに関する問い合わせは、サイト最下部に記載のメールアドレスか @Surgo にお願いします。

はじめに

Python は Google で使われている主要なスクリプト言語です。 このスタイルガイドは Python によるプログラムにおいてすべきこと、 すべきでないことをまとめています。 正しくコードを書くために、 Vim 用の設定ファイル を作成しました。 Emacs は初期設定のままで問題ありません。

Python 言語のルール

pychecker

コードに pychecker を実行する。

定義:
Pychecker は Python のソースコード内のバグを発見するためのツールです。 C や C++ のような、非動的言語のコンパイラが引き起こすような問題を発見します。 lint とよく似ています。 Python の動的な特性により、いくつかの警告は正確ではない可能性があります - とはいえ、不正確な警告はほとんどありません。
利点:
タイプミス、未初期化変数の利用などの単純ミスを発見できます。
欠点:
pychecker は完璧ではありません。利用するために、a) コードを書き b) 警告の無効化 c) 改修する もしくは d) 無視する 等が必要になることがあります。
結論:

コードに対し、 pychecker を必ず実行します。

pychecker の実行方法については pychecker ホームページ を参照してください。

警告を無効にするには、無効にしたい警告を __pychecker__ というモジュールレベル変数に設定します。 例)

__pychecker__ = 'no-callinit no-classattr'

この手法により、警告の無効化や有効化が簡単に行えるという利点があります。

pychecker のすべての警告は、 pychecker --help で取得できます。

未使用変数に関する警告を無効にしたい場合は、 未使用変数の識別子として '_' を利用するか、 変数名のプレフィックスに 'unused_' を指定します。 変数名を変更できない場合は、 関数の先頭に記載します。 例)

def foo(a, unused_b, unused_c, d=None, e=None):
    (d, e) = (d, e)  # pychecker 対応
    return a

その "未使用の宣言" が本当に使われていないかを pychecker により確認するのもいいでしょう。

インポート

パッケージもしくはモジュールのみを import する。

定義:
あるモジュールから別のモジュールのコードを利用する再の再利用性を高めます。
利点:
名前空間の管理方法はシンプルです。 各識別子に対応するソースと一致しています; x.Obj は、その Obj がモジュール x に定義されていることを意味します。
欠点:
モジュール名の衝突が懸念されます。 モジュール名が長すぎるものがあります。
結論:

パッケージとモジュールのインポートは import x を利用する。

x がパッケージの接頭辞、 y が接頭辞でないモジュール名の場合は from x import y を利用する。

モジュール y を 2 つインポートする必要がある場合や、 y が長すぎる場合は from x import y as z を利用する。

例えば、 sound.effects.echo というモジュールの場合は以下のようにインポートする:

   from sound.effects import echo
   ...
   echo.EchoFilter(input, output, delay=0.7, atten=4)

相対パスによるインポートはしない。
モジュールが同じパッケージ内にある場合においても、絶対パスを利用する。
これにより同じパッケージを意図せずに複数回インポートするのを防ぐことができます。

パッケージ

モジュールのフルパスを使って各モジュールをインポート、参照する。

利点:
モジュール名の干渉を防ぐことができます。モジュールを追いかけるのが簡単になります。
欠点:
パッケージの階層構造も複製する必要があるため、コードのデプロイが難しくなります。
結論:

すべての新しいコードでは、モジュールはその基となるパッケージ名から参照します。

以下のようにインポートします:

# Reference in code with complete name.
import sound.effects.echo

# Reference in code with just module name.
from sound.effects import echo

例外

例外は慎重に利用する。

定義:
例外は、コードブロックの正常処理から抜け、エラーや異常を処理するための手段です。
利点:
正常処理コードの制御フローと、エラー処理用のコードを明確化できます。 また、特定の異常が発生した際に、複数フレームの処理を飛ばすように制御できます。 例えば、すべて実行した後にエラーコードを返すのではなく、ネストした関数からワンステップで戻せます。
欠点:
処理のコントロールが複雑になるので注意する必要があります。 ライブラリーを呼び出す際の、エラーを発見しにくくしてしまう可能性があります。
結論:

例外は一定の条件でのみ利用する。

  • 例外の発生: raise MyException("Error message")raise MyException とします。 2 つの変数からなる例外 (raise MyException, "Error message") や 文字列ベースの例外 (raise "Error message") は推奨しません。

  • モジュールやパッケージは、ビルトインの Exception クラスを継承した、固有の例外クラスを定義します。 モジュールの基底例外クラスは Error とします。:

    class Error(Exception):
        pass
    
  • 再度同じ例外を発生させる場合や、スレッドの最上部ブロックの場合 (エラーメッセージを出力する) を除き、 すべての例外を処理 (キャッチオール) する except: 構文を使用せず、 ExceptionStandardError をキャッチします。 Python は except: が非常に寛容なため、 Python 構文エラーを含むすべての例外をキャッチします。 そのため except: は真のバグを隠してしまう可能性があります。

  • try/except 内は、必要最小限のコードにします。 try 内が多いと、想定していた例外以外の例外が発生する可能性があります。 その場合、 try/except ブロックにより真のバグが隠れてしまう可能性があります。

  • finally 句を利用し、 try 内での例外の発生に関係なく処理を実行させることができます。 これはファイルを閉じるなどのクリーンアップに便利です。

グローバル変数

グローバル変数は避ける。

定義:
変数はモジュールレベルで宣言します。
利点:
場合によっては便利です。
欠点:
モジュールレベルの変数は、モジュールをインポートした際に割り当てられるので、 インポートの際にモジュールの動作が変わってしまう可能性があります。
結論:

グローバル変数でなく、クラス変数を利用します。ただし、以下の場合を除きます:

  • スクリプトのデフォルトオプション
  • モジュールレベル定数。例えば PI = 3.14159 などです。 定数はすべて大文字とアンダーバーからなる名前にします。詳細は :ref:`ネーミング` を参照のこと。
  • 関数によって必要、もしくは返される値をグローバルにキャッシュする場合などには便利です。
  • もし必要な場合、グローバルはモジュールの内部で作成し、 パブリックモジュールレベルの関数によりアクセスされる必要があります; 詳細は :ref:`ネーミング` を参照のこと。

ネスト/ローカル/インナー クラスと関数

ネスト/ローカル/インナー クラス、及び関数は有効です。

定義:
クラス内部に、メソッド、関数、クラスを定義できます。 関数内部に、メソッド、関数を定義できます。 ネストされた関数は、再内スコープ内に定義された変数に読取専用でアクセスします。
利点:
特定のスコープ内に限定して利用するユーティリティークラスや関数を定義できます。 抽象データ型 です。
欠点:
ネスト、ローカルクラスのインスタンスはシリアライズ (pickle) できません。
結論:
これはとても有効です。

リストの内包

シンプルなケースの場合のみ利用する。

定義:
リスト内包表記とジェネレータ式は、 map()filter()lambda に頼ることなく、 配列やイテレータを作成する簡単で効率的な方法を提供します。
利点:
シンプルなリスト内包表記は、他の配列を作成する手法よりも分かりやすく簡単です。 ジェネレータ式は完全な配列を作成しない (遅延評価) ため、とても効率的です。
欠点:
複雑なリスト内包表記やジェネレータ式は可読性が低くなります。
結論:

シンプルなケースの場合のみ利用するようにしましょう。 以下の各部はワンライナーを適用します: マッピング式、 for 式、フィルター式。 複数の for 式、フィルター式は許可されません。 複雑になりそうな場合は、ループ式を代用してください:

# No:
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

return ((x, y, z)
        for x in xrange(5)
        for y in xrange(5)
        if x != y
        for z in xrange(5)
        if y != z)
# Yes:
result = []
for x in range(10):
    for y in range(5):
        if x * y > 10:
            result.append((x, y))

for x in xrange(5):
    for y in xrange(5):
        if x != y:
            for z in xrange(5):
                if y != z:
                    yield (x, y, z)

return ((x, complicated_transform(x))
        for x in long_generator_function(parameter)
        if x is not None)

squares = [x * x for x in range(10)]

eat(jelly_bean for jelly_bean in jelly_beans
    if jelly_bean.color == 'black')

標準イテレータと式

配列、辞書、ファイルなど、それに提供されている標準のイテレーターや式を利用する。

定義:
辞書や配列のようなコンテナ型は、標準のイテレータやメンバを確認するための式 ("in" や "not in") が定義されています。
利点:
標準のイテレータや式はシンプルで効率的です。 余計なメソッドを呼び出すことなく、直接その式を利用できます。 標準の操作を利用する関数が一般的です。 その式をサポートするどんな型でも利用が可能となります。
欠点:
メソッドの名前からオブジェクトの型を見分けることができなくなります (例えば、 has_key() は辞書です)。 それは利点でもあります。
結論:

配列、辞書、ファイル等は、その標準のイテレータや式を使います。 イテレータメソッドはビルトインの型にも定義されています。 配列を返すメソッドよりもそのようなメソッドを優先します。 繰り返し処理中に、コンテナを変更してはいけません。:

# Yes:
for key in adict: ...
if key not in adict: ...
if obj in alist: ...
for line in afile: ...
for k, v in dict.iteritems(): ...
# No:
for key in adict.keys(): ...
if not adict.has_key(key): ...
for line in afile.readlines(): ...

ジェネレータ

必要に応じ、ジェネレータを利用する。

定義:
ジェネレータ関数は、 yield 分が実行されるたびに値を生成 (yeild) するイテレータを返します。 値の生成後、ジェネレータ関数のランタイムは、次の値が必要とされるまで待機状態となります。
利点:
ローカル変数及び制御フローが呼び出されるたびに保持されるため、コードが簡潔です。 ジェネレータは、一度にすべての値を生成する関数よりもメモリを消費しません。
欠点:
なし。
結論:
必要に応じ利用します。ドキュメンテーション文字列 は "Returns:" ではなく "Yields:" を利用します。

Lambda 関数

ワンライナーに利用する。

定義:
Lambda は実行文とは対照的に、式の中に匿名関数を定義します。 それは多くの場合、 map()filter() などの高階関数のためのコールバックや式の定義に利用されています。
利点:
とても便利です。
欠点:
ローカル関数と比較すると、可読性が低く、デバッグも難しいです。 匿名であるということは、スタックトレースが分かりにくくなることを意味します。 関数に、式以外を含むことができないという制限があります。
結論:

ワンライナーに利用します。 もしラムダ関数内のコードが 60 ~ 80 文字より長い場合は、 標準の (ネスト) 関数を定義するほうがいいでしょう。

掛け算のような一般的な式は、lambda 関数ではなく operator モジュールの関数を利用します。 例えば、 lambda x, y: x * y ではなく operator.mul を利用します。

変数の初期値

大抵の場合に利用する

定義:
関数の引数配列の末尾に、例えば def foo(a, b=0): のような変数の値を指定できます。 もし 1 つの引数で foo が呼びだされた場合、 b0 となります。 もし 2 つの引数で呼び出された場合、 b は 2 つめの引数の値となります。
利点:
たいていは初期値で動作し、必要に応じて初期値を上書きする関数です。 特殊ケースのために複数の関数を定義するのではなく、 変数の初期値を指定することで、簡単に実現できます。 また、Python はメソッド/関数のオーバーロードをサポートしませんが、 変数の初期値によりオーバーロードのような使い方ができます。
欠点:
変数の初期値は、モジュールがロード時に一度だけ評価されます。 変数が配列や辞書のようなミュータブルなオブジェクトの場合は問題が発生するかもしれません。 例えば関数が配列にアイテムを追加するなど、オブジェクトを変更した場合は初期変数が変わってしまいます。
結論:

以下に注意して利用します:

ミュータブルなオブジェクトは、関数やメソッドで定義された変数の初期値に指定しないようにしましょう:

# Yes:
def foo(a, b=None):
    if b is None:
        b = []
# No:
def foo(a, b=[]):
    ...

初期値が設定された変数は変数名を指定します。 これはコードをドキュメント化する際の助けとなり、 変数が追加された際にインターフェースが壊れてしまうのを防ぐことができます:

def foo(a, b=1):
    ...
# Yes:
foo(1)
foo(1, b=2)
# No:
foo(1, 2)

プロパティ

データを設定したりアクセスするために、簡単で軽量なアクセサやセッターメソッドを用いたプロパティを利用する。

定義:
属性へのゲッター、セッターメソッドをラップし、軽量言語の標準的な属性アクセスを利用する。
利点:
単なる属性へのアクセスに、ゲッター、セッターメソッドを使わないことで可読性が向上します。 計算が軽量になります。 クラスのインターフェースを維持するための Pythonic な考え方です。 パフォーマンスに関して、変数への直接アクセスが理にかなっている場合は、 通常のアクセサメソッドをプロパティーへ置き換える必要があります。 これはアクセサメソッドがインターフェースを変更することなく機能を追加できるようにします。
欠点:
ゲッター、セッターメソッドを宣言した後にプロパティを指定する必要があり、 コードより下にプロパティーとして利用することを通知しなければなりません (読取専用のプロパティーを作成するための @property は除く - 下部参照)。 object から継承する必要があります。 演算子オーバーロードのような副次作用を回避できます。 サブクラスで分かりにくい場合があります。
結論:

データを設定したりアクセスするために、簡単で軽量なアクセサやセッターメソッドを用いたプロパティを利用します。 読取専用のプロパティーは @property デコレータで作成します。

もしプロパティがオーバーライドしたものではない場合、そのプロパティが継承できるか分かりません。 この場合、サブクラスでオーバーライドするメソッドがプロパティーから呼出されるとき、 アクセサメソッドが間接的に呼出されることに注意してください (Template Method パターン を利用する)。:

# Yes:
class Square(object):
    """A square with two properties: a writable area and a read-only perimeter.

    To use:
    >>> sq = Square(3)
    >>> sq.area
    9
    >>> sq.perimeter
    12
    >>> sq.area = 16
    >>> sq.side
    4
    >>> sq.perimeter
    16
    """

    def __init__(self, side):
        self.side = side

    def __get_area(self):
        """Calculates the 'area' property."""
        return self.side ** 2

    def ___get_area(self):
        """Indirect accessor for 'area' property."""
        return self.__get_area()

    def __set_area(self, area):
        """Sets the 'area' property."""
        self.side = math.sqrt(area)

    def ___set_area(self, area):
        """Indirect setter for 'area' property."""
        self._SetArea(area)

    area = property(___get_area, ___set_area,
                    doc="""Gets or sets the area of the square.""")

    @property
    def perimeter(self):

        return self.side * 4

True/False の評価

可能な場合は、非明示的な false を利用する。

定義:
Python は、ブール値コンテキストで特定の値を false と評価します。 "大雑把" にいうと、"空" の値を false と評価するため、 0, None, [], {}, "" のすべての評価は、 ブール値コンテキストでは false となります。
利点:
Python のブール値を使うと、可読性が高まり、エラーを防ぐことができます。 さらにほとんどの場合で、これは高速です。
欠点:
おそらく、C/C++ 開発者は違和感を感じるかもしれません。
結論:

例えば、 if foo != []: ではなく if foo: のような比明示的名 false を利用します。 心に止めて置くべき 2 ~ 3 の注意事項があります。

  • None との比較に ==!= を利用してはいけません。 isis not を利用します。

  • if x is not None: を意図してる際の if x: には注意が必要です -- 変数や引数をテストする際、初期値 None に対して何らかの値をセットしたとします。 しかし、他の値 (0, [] 等) もブール値コンテキスト内で false の可能性があります。

  • ブール変数は == を使って False と比較してはいけません。 if not x: を代用します。 もし、 FalseNone を区別する必要がある場合は、 if not x and x is not None: のように評価をつなげます。

  • シーケンス (文字列、配列、タプル) の場合、 空のシーケンスも確実に false とするため、 if len(seq):if not len(seq): よりも if not seq:if seq: が好ましいです。

  • 整数を取り扱う場合、非明示的な false は利点ではなく欠点になるかもしれません (0None と扱うかもしれません)。 数値 0 と数値であるかもしれない値 (len() の結果ではない) を比較してしまうかもしれません。:

    # Yes:
    if not users:
        print 'no users'
    
    if foo == 0:
        self.handle_zero()
    
    if i % 10 == 0:
        self.handle_multiple_of_ten()
    
    # No:
    if len(users) == 0:
        print 'no users'
    
    if foo is not None and not foo:
        self.handle_zero()
    
    if not i % 10:
        self.handle_multiple_of_ten()
    
  • '0' (例えば文字列の 0) の評価は true です。

非推奨機能

可能な場合は、 string モジュールではなく string メソッドを利用する。 apply の代わりに関数呼び出しシンタックスを利用する。 filtermapreduce ではなく、リスト内包表記や for ループを利用する。

定義:
Python の現行バージョンでは、一般的に好ましいとされる別の構造が提供されています。
結論:

今後、これらのより好ましい機能をサポートしていないバージョンの Python を使うことはないので、 新しいスタイルを利用しましょう。:

# No:
words = string.split(foo, ':')

map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))

apply(fn, args, kwargs)
# Yes:
words = foo.split(':')

[x[1] for x in my_list if x[2] == 5]

fn(*args, **kwargs)

レキシカル (静的) スコープ

利用する。

定義:

Python のネスト関数は、関数のスコープに定義した変数を参照することはできますが、代入はできません。 変数は、静的プログラムテキストに基づくレキシカル (静的) スコープを利用してその束縛から解放されます。 ブロック内のどの宣言を利用する場合でも、 Python はその宣言がローカル変数であるように (宣言より前の利用でも) アクセスできるようにします。 もしグローバル宣言をした場合は、名前はグローバル変数とみなされます。

この機能の利用例です

def get_adder(summand1):
    """Returns a function that adds numbers to a given number."""
    def adder(summand2):
        return summand1 + summand2

    return adder
利点:
うまく利用すれば、より分かりやすく素敵なコードになります。 特に、LISP と Scheme (と Haskell と ML と ...) のプログラマーはうれしく思うでしょう。
欠点:

バグが見つけにくくなってしまいます。例えば PEP-0227 に基づく例です

i = 4
def foo(x):
    def bar():
        print i,
    # ...
    # A bunch of code here
    # ...
    for i in x:  # Ah, i *is* local to Foo, so this is what Bar sees
        print i,
    bar()

foo([1, 2, 3]) の出力結果は 1 2 3 3 となり、 1 2 3 4 にはなりません。

結論:
利用しましょう。

関数/メソッドのデコレータ

明確な利点がある場合に、デコレータを慎重に利用する。

定義:

関数やメソッドへのデコレータ ("@ 表記法" として知られています)。 最も一般的なデコレータは AWS Solution Division@staticmethod であり、 メソッドをクラスメソッドやスタティックメソッドとして定義します。 デコレータ構文は同様にユーザ定義のデコレータも考慮しています。 詳しくは my_decorator 関数を見てください:

class C(object):
    @my_decorator
    def method(self):
        # method body ...

これは以下と等しいです:

class C(object):
    def method(self):
        # method body ...
    method = my_decorator(method)
利点:
素敵なことにメソッドを若干変更するだけです。 その変更により、重複しているコードや不変条件の集約が可能となります。
欠点:
デコレータは関数の引数や戻り値に対して任意の操作ができますが、 予期しない動作を返す恐れがあります。 さらに、デコレータはインポート時に実行されます。 デコレータコードの不具合は、復帰がほぼ不可能です。
結論:

明確な利点がある場合に、デコレータを慎重に利用します。 デコレータは関数と同様に、インポート や ネーミング のガイドラインに準拠します。 デコレータの pydoc はこの関数がデコレータであることを明確に記載します。 デコレータに関する単体テストを実施してください。

デコレータを実行した時点 (おそらく pychecker やその他ツールからのインポート時) で利用できないかもしれないので、 デコレータ自体の外部依存 (例えば、ファイルやソケット、データベースコネクションへの依存) を避けます。 正常なパラメータでのデコレータの呼び出しは、 (できる限り) すべてのケースにおいて成功を保証しなければなりません。

デコレータは "トップレベルのコード" の特殊ケースです - 詳細は :ref:`メイン_関数` を参照してください。

スレッド

ビルトイン型の原子性 (Atomicity) を信頼しない。

結論:

Python の辞書のようなビルトインデータ型は原始的 (Atomic) な命令実行ができるように見えますが、 ごくまれに原始的でない (例えば、 __hash____eq__ が Python メソッドとして実行した場合) やっかいなケースがあり、 原始性を信頼するべきではありません。 さらに、原始的な変数の割り当て (その順番が辞書に依存していることから) も信頼するべきではありません。

スレッド間でデータを交換するために推奨されている方法は、 Queue モジュールの Queue データ型の利用です。 他には、 threading モジュールとそのプリミティブロック (primitive lock) を利用できます。 よりローレベルなロックの代わりに threading.Condition を使えるように、 一般的な 条件変数 (condition variable) の使用方法を学んでください。

強力な機能

このような機能は避ける。

定義:
Python はとても柔軟な言語であり、 メタクラス、バイトコードへのアクセス、高速コンパイル、動的な継承、オブジェクトの親の変更、インポートハック、リフレクション、内部システムの変更 など多くの素敵 (変態的) な機能があります。
利点:
これは言語の強力な機能です。これはコードをさらに軽量にできます。
欠点:
このような機能を必要としない場合においても、これら素敵な機能は非常に魅力的でしょう。 しかし、このような機能を含むコードはとても可読性が低く、分かりづらく、 デバッグが難しいでしょう。 この方法は最初は高速 (オリジナル作者にとって) ですが、 コードを再確認する必要がある場合、 より長いコード (標準的なコード) の方が読みやすくメンテナンス性にすぐれている傾向があります。
結論:
このような機能は避けましょう。

Python スタイルルール

セミコロン

行をセミコロンで終了、また 2 つの命令を同じ行内に書くためにセミコロンは使用しません。

行の長さ

行の最大長は 80 文字にする。

例外: Python 2.4 以前を利用する場合のみ、モジュールをインポートする行が 80 文字を超える可能性があります。

バックスラッシュによる行継続は利用しない。

丸括弧(parentheses)、角括弧(square bracket)、波括弧内で、Python の 非明示的な行継続 を利用します。 必要な場合は、追加の括弧で式を囲むことができます:

# Yes:
foo_bar(self, width, height, color='black', design=None, x='foo',
        emphasis=None, highlight=0)

    if (width == 0 and height == 0 and
        color == 'red' and emphasis == 'strong'):

リテラル文字列が 1 行で収まらない場合は、括弧を利用した非明示的な行継続をします:

x = ('This will build a very long long '
     'long long long long long long string')

上記の行連結例のように各要素のインデントに注意します。詳しくは :ref:`インデント` セクションを参照してください。

括弧

括弧の利用は必要最小限とします。

return 構文や条件式では、非明示的な行継続以外 (:ref:`行の長さ` 参照) の目的で括弧を利用しません。 括弧はタプルのために利用します:

# Yes:
if foo:
    bar()
while x:
    x = bar()
if x and y:
    bar()
if not x:
    bar()
return foo
for (x, y) in dict.items(): ...
# No:
if (x):
    bar()
if not(x):
    bar()
return (foo)

インデント

コードブロックのインデントはスペース 4 つとします。

タブ、タブとスペースの組み合わせは絶対に利用しないようにします。 非明示的な行継続以外の場合、 :ref:`行の長さ` で例示されているように各要素を縦方向にそろえます。 もしくは、スペース 4 つのぶら下がりインデントを利用する場合は、変数が最初の行に存在してはいけません:

# Yes:
# Aligned with opening delimiter
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# 4-space hanging indent (ぶら下がりインデント); nothing on first line
foo = long_function_name(
    var_one, var_two, var_three,
    var_four)
# No:
# Stuff on first line forbidden
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# 2-space hanging indent forbidden
foo = long_function_name(
  var_one, var_two, var_three,
  var_four)

空行

トップレベルの定義間は 2 行改行し、メソッド定義間は 1 行改行します。

トップレベルの関数やクラスなどの定義間は 2 行改行します。 クラス定義行と最初のメソッド定義や、メソッドの定義間は 1 行改行します。 関数やメソッド内での改行は適切であると判断した場合のみです。

空白

句読点での空白の利用は標準的なタイピングの規則に準拠します。

丸括弧(parentheses)、角括弧(square bracket)、波括弧内には空白を入れません:

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

コンマ、セミコロン、コロンの前には空白を入れません。 行の終わりのコンマ、セミコロン、コロンの後には空白を入れます:

# Yes:
if x == 4:
    print x, y
x, y = y, x
# No:
if x == 4 :
    print x , y
x , y = y , x

引数、配列、スライスの開始である丸括弧(parentheses)、角括弧(square bracket) を開く前には空白を入れません。

# Yes:
spam(1)
# No:
spam (1)
# Yes:
dict['key'] = list[index]
# No:
dict ['key'] = list [index]

代入 (=)、 比較 (==, <, >, !=, <>, <=, >=, in, not in, is, is not)、 評価 (and, or, not) などの項演算子の両側には空白を入れます。 算術演算子の両側の空白は個人判断であるが、 項演算子の両側には空白文字を入れます:

# Yes:
x == 1
# No:
x<1

キーワードの値や初期値のための '=' 記号の両側には空白を入れません。

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

メンテナンス性の低下につながるため、 連続する行を垂直にそろえるために空白は入れません (:, #, =, 等):

# Yes:
foo = 1000  # comment
long_name = 2  # comment that should not be aligned

dictionary = {
    "foo": 1,
    "long_name": 2,
    }
# No:
foo       = 1000  # comment
long_name = 2     # comment that should not be aligned

dictionary = {
    "foo"      : 1,
    "long_name": 2,
    }

Python インタプリタ

モジュールは #!/usr/bin/env python<version> で開始します。

モジュールは、プログラムを実行するために用いるパイソンインタプリタを指定する "shebang" 行で開始します。

#!/usr/bin/env python2.4

例えば /usr/bin/python2 ではなく /usr/bin/python2.4 のような、常に利用している特定のバージョンを指定します。 例えば /usr/bin/python2 が Python 2.0.1 か Python 2.3.0 のどちらか ? など 異なるバージョンの Python にアップデートする際、依存の解決を簡単にし、 使用しているバージョン間の衝突や破損を回避します。

コメント

ドキュメンテーション文字列 (Doc Strings)

Python には独自のコメント形式を利用したドキュメンテーション文字列があります。 ドキュメンテーション文字列はパッケージ、モジュール、クラスまたは関数の最初のステートメントです。 これら文字列はオブジェクトの __doc__ を介して自動的に抽出し、 pydoc として利用されます。 (pydoc をモジュールに実行して、それがどのように表示されるか試してください) ドキュメンテーション文字列は、3 つのダブルクォーテーションで囲まれた文字列というのが慣例です。 ドキュメンテーション文字列は、 ピリオド、クエスチョンマーク、エクスクラメーションマークで終了する概要を記述した行 (一行)、 その下に空行、 その下に最初のダブルクォーテーションと同じカーソル位置から始まる残りの詳細なドキュメンテーション文字列から構成されています。

以下に、より詳細なドキュメンテーション文字列のガイドラインを記載しています。

モジュール

すべてのファイルは以下のアイテムを確実に含む必要があります。

  • 著作権表記 (たとえば、 Copyright 2008 Google Inc.)
  • ライセンス定型文。プロジェクトが利用するライセンスの適切な定型文 (例えば、Apache 2.0、BSD、LGPL、GPL)
  • ファイルの原作者が分かる著作者表記

関数及びメソッド

一見わかりにくかったり、長い関数やメソッドはドキュメンテーション文字列が必要です。 それに加え、一目で理解できたり、短い関数であっても、外部からアクセス可能な関数やメソッドであればドキュメンテーション文字列が必要です。 ドキュメンテーション文字列は関数の動作と入出力の詳しい解説を含む必要があります。 それは通常、そのアルゴリズムが複雑でない限りその動作について詳しく解説する必要はありません。 コード内の効果的なコードブロックやインラインコメントを利用することでよりよくなります。 ドキュメンテーション文字列は、コードを 1 行も見ることなく、その関数を呼び出すための十分な情報が記載されている必要があります。 引数は、2 もしくは 4 つのぶら下げインデントで縦にそろえ、コロンの後にその説明を記載する必要があります。 ドキュメンテーション文字列は、期待される戻り値の型を指定します。 "Raises:" 部分には関数により発生する可能性があるすべての例外を列挙します。 ジェネレータ関数のドキュメンテーション文字列は "Returns:" よりも "Yields:" を使います。

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
    """Fetches rows from a Bigtable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by big_table.  Silly things may happen if
    other_silly_variable is not None.

    Args:
        big_table: An open Bigtable Table instance.
        keys: A sequence of strings representing the key of each table row
            to fetch.
        other_silly_variable: Another optional variable, that has a much
            longer name than the other args, and which does nothing.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings. For
        example:

        {'Serak': ('Rigel VII', 'Preparer'),
         'Zim': ('Irk', 'Invader'),
         'Lrrr': ('Omicron Persei 8', 'Emperor')}

        If a key from the keys argument is missing from the dictionary,
        then that row was not found in the table.

    Raises:
        IOError: An error occurred accessing the bigtable.Table object.
    """
    pass

クラス

クラスには、クラス定義の直下にそのクラスを説明するドキュメンテーション文字列を記載する必要があります。 クラスがパブリックの属性を有している場合は、関数の変数部分と同様に、 Attributes にドキュメンテーションを記述します。

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

ブロック/行内のコメント

最後にコメントを記述するのは、コードの複雑な箇所です。 もし コードレビュー 等で説明する必要がある場合は、注釈を入れておく必要があります。 複雑な演算の前に、2 から 3 行のコメントを記載します。 わかりにくい演算は行の終わりにコメントを記載します。

# We use a weighted dictionary search to find out where i is in
# the array.  We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.

if i & (i-1) == 0:        # true iff i is a power of 2

可読性を向上するため、コメントはコードから少なくとも 2 つ空白を開ける必要があります。

また、決してコードを記載してはいけません。コードを読んでいる人は Python に精通していると仮定します。

# BAD COMMENT: Now go through the b array and make sure whenever i occurs
# the next element is i+1

クラス

どのクラスからも継承のないクラスは、かならず object を継承します。ネストクラスについても同様です。

# No:
class SampleClass:
    pass

class OuterClass:

    class InnerClass:
        pass
# Yes:
class SampleClass(object):
    pass

class OuterClass(object):

    class InnerClass(object):
        pass

class ChildClass(ParentClass):
    """Explicitly inherits from another class already."""

object の継承は、プロパティを適切に動作させるために必要であり、 Python 3000 の潜在的な非互換性から保護します。 それは、 __new__, __init__, __delattr__, __getattribute__, __setattr__, __hash__, __repr__, や __str__ を含む object のデフォルトの意味 (semantics) を含む特別なメソッドを定義します。

文字列

パラメータがすべて文字列の場合は、その文字列のフォーマットを指定するために % 演算子を利用します。 しかし、 +% のどちらが適切かを判断する必要があります。

# No:
x = '%s%s' % (a, b)  # use + in this case
x = imperative + ', ' + expletive + '!'
x = 'name: ' + name + '; score: ' + str(n)
# Yes:
x = a + b
x = '%s, %s!' % (imperative, expletive)
x = 'name: %s; score: %d' % (name, n)

ループ内の文字列を連結するために ++= 演算子を利用してはいけません。 文字列は イミュータブル であるため、これは不要なテンポラリーオブジェクトを作成し、実行時に線形制約クラスではなく 2 次制約クラスとなります。 その代用として、各文字を配列に入れ、ループ終了後に ''.join で配列を連結します (cStringIO.StringIO バッファーへの追記)。

# No:
employee_table = '<table>'
for last_name, first_name in employee_list:
    employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name)
employee_table += '</table>'
# Yes:
items = ['<table>']
for last_name, first_name in employee_list:
    items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name))
items.append('</table>')
employee_table = ''.join(items)

複数行の文字列は ''' ではなく、 """ を利用します。 しかし、複数行の文字列の連結がプログラムのインデントからはみでないのであれば、 非明示的な行継続の方が美しくなる事に注意しましょう。

# No:
print """This is pretty ugly.
Don't do this.
"""
# Yes:
print ("This is much nicer.\n"
       "Do it this way.\n")

TODO コメント

短期的で解決すべきこと、条件を満たしてはいるがベストではない場合などに、 コードに一時的な TODO コメントを利用します。

TODO は頭に TODO を含む必要があり、続いて括弧内に名前やメールアドレス、もしくはその他の識別情報を記載します。 オプションでコロンをつけます。 コメントで今後どうするかを解説します。 主な目的は、共通の TODO フォーマットにより (検討すべきより詳細な情報を持っている) コメントの記載者が検索できるようにすることです。 TODO は解決策を提供するためのものではありません。

# TODO(kl@gmail.com): Drop the use of "has_key".
# TODO(Zeke) change this to use relations.

もし TODO が、"いついつまでに、なになにする" 形式だった場合は、 必ず特定の日付 ("Fix by November 2009") や 特定のイベント ("Remove this code when all clients can handle XML responses.") を含めます。

インポート書式

インポートは別々の行に分けるべきです。

# Yes:
import os
import sys
# No:
import os, sys

インポートは常にファイルの先頭に置き、 モジュールのコメントやドキュメンテーション文字列の後、 かつモジュールのグローバルや定数の前に記載します。 インポートはジェネリックなものからジェネリックでない順に並び替え、グループ化する:

  • 標準ライブラリーのインポート
  • サードパーティーのインポート
  • アプリケーション固有のインポート

各グループの範囲内で、インポートは辞書記載順、大文字小文字は無視、すべてのパッケージパスを記載する必要があります。

import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar

ステートメント

基本的に 1 行に 1 つのステートメントです。

しかし、ステートメントとその評価結果を同じ 1 行に記載するかもしれません。 特に tryexcept は同じ行にできないため、 try/except ではそのような記述はせず、 else を含まない if の場合にのみそのようにします。

# Yes:
if foo: bar(foo)
# No:
if foo: bar(foo)
else:   baz(foo)

try:               bar(foo)
except ValueError: baz(foo)

try:
    bar(foo)
except ValueError: baz(foo)

アクセス制御

アクセサ関数が必要でない場合は、関数呼び出しにかかる Python の余分なコストを抑えるためにアクセサ関数の代わりに一般の変数を利用します。 関数を追加した場合は、構文を一貫させるため property を利用できます。

他方で、アクセスがより複雑な場合や変数へのアクセスコストが重要な場合は、 get_foo()set_foo() のような関数を利用 (ネーミングガイドラインを参照) し呼び出します。 過去に property 経由でアクセスを許可していた場合は、新しいアクセサ関数をプロパティに結びつけてはいけません。 古いメソッドで変数にアクセスしようとしているコードもあるため、その変更は複雑です。

ネーミング

module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.

非推奨のネーミング

  • カウンターやイテレーター以外の 1 文字の名前
  • あらゆるパッケージ、モジュール名でのハイフン (-)
  • __double_leading_and_trailing_underscore__ (Python で予約された二重アンダーラインで囲まれた名前)

一般的なネーミング

  • "Internal" とはモジュール内部やプロテクト、プライベートクラス内を意味しています。
  • 前にアンダーラインを 1 つ付加 (_) すると、モジュール変数と関数を保護するためのいくつかの機能 (import * from でインポートできない) を提供します。 インスタンス変数や関数の前にアンダーラインを 2 つ付加 (__) すると、その変数やメソッドをプライベートにする (難読化: name-mangling) ことができます。
  • モジュール内に関連するクラスとトップレベル関数を一緒に置きます。 Java とは違い、1 モジュールに 1 つのクラスに限定する必要がありません。
  • クラス名はキャピタライズ (CapWords) し、モジュール名は 小文字とアンダーバー (lower_with_under.py) にします。 多くの CapWords.py という名前の既存モジュールがありますが、 モジュールがクラス名の後に命名されると混乱するため現在これは非推奨です (import StringIO と書いたか from StringIO import StringIO と書いたか)。

Guido の推奨に基づくガイドライン

タイプ 外部 内部
パッケージ lower_with_under  
モジュール lower_with_under _lower_with_under
クラス CapWords _CapWords
例外 CapWords  
関数 lower_with_under() _lower_with_under()
グローバル/クラス 定数 CAPS_WITH_UNDER _CAPS_WITH_UNDER
グローバル/クラス 変数 lower_with_under _lower_with_under
インスタンス 変数 lower_with_under _lower_with_under (protected) or __lower_with_under (private)
メソッド名 lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private)
関数/メソッド パラメータ lower_with_under  
ローカル変数 lower_with_under  

メイン 関数

インポートが必要なスクリプトでも、 単純に main() 関数で実行する場合でも、 スクリプトの主要な機能の実行に差異があってはいけません。 メイン 関数は main() 関数である必要があります。

Python においては、 pycheckerpydoc と単体テストはモジュールがインポート可能であることが必要です。 モジュールのインポート時にメイン 関数が実行されないように、 メインプログラムを実行する前に if __name__ == '__main__' で常にチェックする必要があります。

def main():
    ...

if __name__ == '__main__':
    main()

モジュールのインポート時にトップレベルのコードはすべて実行されます。 関数を呼ばないように注意し、オブジェクトの作成、 pycheckedpydoced の際に実行されてはいけない他の式を実行しないようにします。

おわりに

If you're editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around all their arithmetic operators, you should too. If their comments have little boxes of hash marks around them, make your comments have little boxes of hash marks around them too.

The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you're saying rather than on how you're saying it. We present global style rules here so people know the vocabulary, but local style is also important. If code you add to a file looks drastically different from the existing code around it, it throws readers out of their rhythm when they go to read it. Avoid this.

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.