やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Pythonのコーディング規約を調べてみた

Pythonのコーディング規約を調べてみた。

今回から

前回までのOAuth2.0やGoogle Web APIとの格闘から一旦離れる。Pythonの勉強をざっくりやってみる。

ググった

"python 命名規則"でググったらこちらがヒット。PEP8というPython用スタイルガイドがあるらしい。感謝。この記事よりPEP8を参照すべき。

PEP8

一貫性にこだわりすぎるのは、狭い心の現れである

一貫性にこだわりすぎるのは、狭い心の現れである

いきなりコレである。

前回のくだりからPythonがわからないと嘆き、真っ先にコーディング規約を見にいった私は、一貫性にこだわりすぎる心の狭い人間なのだろう。

まさかの人格否定に動揺するも、OAuth2.0という強敵と戦った私はこの程度の精神攻撃でゆさぶられるほどヤワではない。泣きながら読みすすめていく。

インデント

1レベルインデントするごとに、スペースを4つ使いましょう。

私は4タブ派なのに…。

インデントの項を読んでみると複雑だった。4つがいいとか、4つも必要ないとか。なぜこんなに複雑なんだ?

タブか、スペースか?

スペースが好ましいインデントの方法です。

……なんだと?

その理由が書いていない。でも、「はじめに」のほうにあった。

コードは書くよりも読まれることの方が多い

だから、書き易さより、読み易さのほうが重要だと。

タブは表示幅の設定次第で表示が崩れる。結果、読みづらくなる。対してスペースなら、設定に依存せずに表示できる。作者が編集したとおりに。よってスペースが好ましい。ということだろうか?

1行の長さ

すべての行の長さを、最大79文字までに制限しましょう。

これはよくあるやつ。大抵は80文字以内だと思うけど似たようなもの。

docstring やコメントは72文字

docstringってドキュメント作成するためのコメントのこと?

バックスラッシュ

Pythonでは、複数行を1行として認識するためにはバックスラッシュが必要なことがある。

()[]で囲まれている部分は1行として認識できるため、バックスラッシュは不要らしい。

中途半端だな…。VisualBasic.NETでも似たような仕様があった気がする。ダサい。

空行

トップレベルの関数やクラスは、2行ずつ空けて定義するようにしてください。

以前使ったGoogleのサンプルコードも2行の空行があるところがあった。

あれもコーディング規約だったのか?

ソースファイルのエンコーディング

Python のコアディストリビューションに含まれるコードは常に UTF-8 (Python 2 では ASCII) を使用すべきです。

え、「Python 2 では ASCII」なの?日本語…。

ASCII (Python 2) や UTF-8 (Python 3) を使用しているファイルにはエンコーディング宣言を入れるべきではありません。

デフォルトのエンコーディングを使っているならエンコーディング宣言を入れるなってことか。じゃ、Python2でUTF-8(日本語)使うなら宣言入れていいのね。

いつでも英単語を使うべきです。

日本g

世界中の人が利用するオープンソースプロジェクトは、これと似たポリシーを採用することを推奨します。

英語が読み書きできない私涙目。似たポリシーでいいならカタカナ英語のルー語で戦うか。

import

import文は、通常は行を分けるべきです

しかし、次のやり方はOKです: from subprocess import Popen, PIPE

以前使ったGoogleのサンプルコードみたいにimport urllib2, urllib, simplejson, sys, httplibとしているのはNGと。

モジュールレベルの二重アンダースコア変数名

all, author, version のような、モジュールレベルの “二重アンダースコア変数” (変数名の前後にアンダースコアが2つ付いている変数) は、モジュールに関する docstring の後、そして from future 以外の あらゆるimport文の前に置くべきです。

何を言っているのかわからない。特殊な変数なのか?置き場所の前に、それらの変数が何なのか知らない。

文字列に含まれる引用符

Python では、単一引用符 ' で囲まれた文字列と、二重引用符 " で囲まれた文字列は同じです。

できるだけエスケープ文字を使わずに済むよう、二種類を使い分けるのがいいか。

式や文中の空白文字

イライラの元

らしい。

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

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

確かに多少は気になるが、イライラはしない。どちらかというと、Pythonのインデントに対する気配りの必要性のほうがイライラする。この程度でイラつくのは狭い心の現われじゃないか?

良い: if x == 4: print x, y; x, y = y, x

悪い: if x == 4 : print x , y ; x , y = y , x

話は変わるけど、jsonをみると、なぜかコロン:の前はスペースないのに、後ろにはスペースがある。なぜ?

こちらに回答があった。なるほど、カンマやピリオドと同じ扱いと考えれば覚えやすい。でも、jsonは文章ではない。時刻の表示のときだって……いかん、統一性にこだわりすぎている。狭い心の現われだ。

良い例

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 : : upper]
ham[ : upper]

って、1: 9が悪い例になってるやん。

しかし、スライスではコロンは二項演算子のように振る舞います。よって、(コロンは優先度が最も低い演算子として扱われるので)両側に同じ数(訳注: 無しでも可だと思われる)のスペースを置くべきです。

ということらしい。なるほどわからん。スライスってことは、部分文字列の取得ってこと?ham[1: 9]とやらは、ham文字列中の1文字目から9文字分の文字を取得する、とかそういうこと?だめだPython読めない。

とにかく、複雑なルールってことがわかった。:文字だからといって前スペースなし、後ろスペースあり、みたいに単純には決められない。文脈から判断してスペースの有無を決定せねばならないと。

めんどくせ。

極めつけは以下。良い例、悪い例の順。

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)

こまかすぎる。

二つ以上のスペースを絶対に使わないでください。

とまであった。そこまで?

なるほど、心が狭いという意味がわかってきた。これはこだわりすぎ。まるで私の心が狭いかのように言われたように感じたが「これほど詳細な内容であるこの規約にこだわりすぎる人は心が狭い」という意味だったのか。自虐的。

良い

if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three()

やらないほうが良い

if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()

え、;使えるの?1行1文のほうが見やすいというのはC言語でも同じだと思う。わかりやすい。

絶対やってはいけない

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()

良いとか悪いとかやらないほうが良いとか絶対やってはいけないとか、そのランク付けも面倒。

if foo == 'blah': do_blah_thing()が、やらないほうが良い絶対やってはいけないの両方の中に入っている。else文があるときは絶対やってはいけないということだろうか。なぜ?良いほうにelse文があるときのも入れてくれたら良かったのに。予想できるけど。

コメント

英語を話さない国出身の Python プログラマの方々へ:あなたのコードが、自分の言葉を話さない人に 120% 読まれないと確信していなければ、コメントを英語で書くようにお願いします。

120%って。確信でしかない時点で100%未満。エンコーディングの項とあわせてみれば「PEPは英語以外認めない」ということだろう。

多様性も国際化も認めぬ心の狭さ。いや、むしろ英語に統一することが国際化なのか?あらゆる国の言語で書くのが最高だろうが現実的でない。それなら英語に統一するほうが合理的か。すなおに英語を勉強すべきか。日本語も不自由なのに。

命名規約

一番重要な原則

実装よりも使い方を反映した名前にすべきです。

実装を知らなくても使えるようなわかりやすい名前にしろということか。

実践されている命名方法

  • b (小文字1文字)
  • B (大文字1文字)
  • lowercase
  • lower_case_with_underscores
  • UPPERCASE
  • UPPER_CASE_WITH_UNDERSCORES
  • CapitalizedWords 注意: CapWords のやり方で略語を使う場合、省略した単語の全ての文字を大文字にします。つまりこのやり方だと、HttpServerError より HTTPServerError の方が良いということになります。
  • mixedCase (はじめの文字が小文字である点が、CapitalizedWords と違います!)
  • Capitalized_Words_With_Underscores (醜い!)
変数名 説明
_single_leading_underscore 内部でだけ使うことを示します。from M import *は、アンダースコアで始まる名前のオブジェクトをインポートしません。
single_trailing_underscore_ Pythonのキーワードと衝突するのを避けるために使われる規約です。
__double_leading_underscore クラス Foobar の boo という名前は _FooBarboo になります。
__double_leading_and_trailing_underscore__ ドキュメントに書かれているものだけを使ってください。

アンダースコアはコードの実行に関わるレベルで影響するのか。

守るべき命名規約

対象 規約
パッケージとモジュールの名前 全て小文字の短い名前にすべき
クラスの名前 CapWords 方式を使うべき
型変数の名前 CapWords 方式を使うべき。Numのような短い名前が好ましい
例外の名前 例外はクラスであるべき(CapWords)。例外の名前の最後にErrorをつけるべき
グローバル変数の名前 __all__の仕組みを使うか、エクスポートしたくないグローバル変数の頭にアンダースコアをつける古い規約を使うべき
関数の名前 小文字のみにすべき。単語をアンダースコアで区切るべき
関数やメソッドに渡す引数 インスタンスメソッドのはじめの引数の名前は常にselfを使ってください。クラスメソッドのはじめの引数の名前は常にclsを使ってください。
メソッド名とインスタンス変数 関数の命名規約を使ってください。公開されていないメソッドやインスタンス変数にだけ、アンダースコアを先頭に付けてください。
定数 大文字で書き、単語をアンダースコアで区切ります。

この辺は参考になりそう。

所感

PEP8のおかげさまで勉強になりました。

正直わからないことだらけだが、これから1つずつ知っていけばいいや。

私のどうでもいい感想や勝手な解釈はネタなので真に受けないでください。イライラの元でしょうが、心の広さを試されている試練と思ってください。