[Pythonクイズ]PEP 8(コードの書き方ルール)の理解度をチェック! 適切な書き方がどれか分かるかな?Pythonステップアップクイズ

PEP 8って知ってます? Pythonで標準的なコーディング規約ですよね。でも、どこまでその内容を理解できていますか? PEP 8の理解度を一緒に試してみましょう。

» 2025年04月01日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「Pythonステップアップクイズ」のインデックス

連載目次

PEP 8に準拠しているのはドレかな? PEP 8に準拠しているのはドレかな?

【問題】

 Pythonでは公式なコーディングスタイルガイドとしてPEP 8が提供されている。以下のコード片の中で、PEP 8に従った書き方となっているものはどれか?(複数選択可)

# 1
mytuple = (0,)

# 2
l = [0, 1, 2]

# 3
myfunc = lambda x: x + 1

# 4
if val is not None:
    do_some_work(val)

# 5
res = (long_name_1 +
       long_long_name_2 +
       long_name_3 -
       long_long_name_4)

PEP 8に従った書き方になっているのはドレ?


かわさき

 どうもHPかわさきです。

 今回はPEP 8(Pythonコーディングスタイルガイド)に従った書き方をしているコード片を選ぶ問題です。好評なら、第2弾、第3弾も考えてみます。こんなクイズがあると面白いなというのがあれば、HPかわさきに教えてくださいね。

 あと、画像の中にはトンチンカンなことを言っている人がいますが、あんまり気にしないであげてくださいね。


【答え】

 答えを以下の画像に示します。PEP 8に従った書き方になっているのを「OK!」、そうでないものを「NG!」としています。

合っていましたか? 合っていましたか?

 それぞれについての説明は解説パートでしていくことにしましょう。


かわさき

 イングランドのプレミアリーグに所属するマンチェスター・シティFCのジョゼップ・グアルディオラ監督の愛称「Pep」と勘違いしていたと彼も分かってくれたようです。よかった。よかった。


【解説】

 以下では問題に挙げたコード片ごとに、PEP 8ではどのようなスタイルが推奨されているかを説明していきます(PEP 8から引用している部分は筆者による訳です)。

1:かっこの前後に余計な空白を含めない

 最初のコード片は以下のようなものでした。

mytuple = (0,)

タプルを変数mytupleに代入

 単にタプルを変数に代入するだけの文ですが、これを以下のようにしていることはありませんか?

mytuple = (0, )

カンマに後に空白文字を入れている

 後者の書き方は実は推奨されていません。PEP 8の「Whitespace in Expressions and Statements」では次のようなときには空白文字を入れないことが推奨されています。

  • 開きかっこの直後、閉じかっこの直前
  • 末尾のカンマ「,」と閉じかっこの間
  • カンマ「,」やセミコロン「;」、コロン「:」の直前
  • etc

 リンク先では空白文字を入れるべきではない状況が他にもいろいろと挙げられていますが、ここでは「末尾のカンマ『,』と閉じかっこの間」に注目しましょう。「末尾のカンマ」とは幾つか(1個以上)の要素をカンマで区切って並べるときの最後のカンマのことです。「(0, )」のカンマはまさにそうしたカンマですよね。そして、その直後にタプルを閉じる閉じかっこが続いています。このようなときには空白文字を入れないことが推奨されています。

 問題文では「mytuple = (0,)」のように空白文字が入っていません。なので、これは「OK!」ということになります。

2:小文字のエル「l」を1文字の変数名として使ってはいけない

 2つ目のコード片は次のようなものでした。

l = [0, 1, 2]

リストを変数lに代入

 全く問題ないように思えますが、どこがダメなのでしょうか? PEP 8の「Prescriptive: Naming Conventions」には『小文字のエル「l」や大文字のオー「O」、大文字のアイ「I」を1文字の変数名として絶対に使わないこと』とあります。

 予想は付くでしょうが、これらの文字が単独で登場した場合、見分けにくいからです。「1」(イチ)なのか「l」(エル)なのか、「0」(ゼロ)なのか「O」(オー)なのか、「l」(エル)なのか「I」(アイ)なのか。よく分からないですよね。

 というわけで、リストを代入するからといって、変数名を安易に「l」としているこのコードは「NG!」です。


かわさき

 とはいえ、対話環境などで、ちょっとコードを試したいときなどに筆者はついやっちゃうことがあります(苦笑い)。でも、普段からそういう名前を使わないような習慣を付けておくべきだとは自覚しています。というわけで、これからは「mylist」や「foo」などを使うようにしたいと思います(皆さんも普段から一時的に使用する変数の名前を考えておくようにしましょう)。


3:ラムダ式を変数に代入しない

 3つ目のコード片は次のようなものでした。

myfunc = lambda x: x + 1

ラムダ式を変数に代入

 ラムダ式を変数に代入すれば、次のように呼び出しが可能です。

val = myfunc(10)

ラムダ式を呼び出す

 しかし、PEP 8の「Programming Recommendations」では「ラムダ式を識別子に直接束縛する代入文を使うのではなく、常にdef文を使う」とされています。

 def文で関数を定義すると、関数オブジェクトの名前が明確になります。これはラムダ式を変数に代入したときとの違いの一つです。試してみましょう。

def myfunc(x):
    return x + 1

print(myfunc)

myfunc = lambda x: x + 1

print(myfunc)

関数とラムダ式の違い

 これを実行してみると、次のようになります。

def文に定義した関数とラムダ式(を代入した変数)の違い def文に定義した関数とラムダ式(を代入した変数)の違い

 def文で定義した関数では関数名の「myfunc」が得られていますが、ラムダ式を代入した変数myfuncについては関数名の代わりに「<lambda>」と表示されています。ささいな差ですが、デバッグ時にトレースバックを追いかけるときなど、関数名が明確な方が役立つときがあるはずです。関数として定義したいものはdef文を使用するようにしましょう。

 ラムダ式の最大の利点は、大きな式の一部に関数的なものを(事前にそれを定義することなく)含められることです。

d = [-10, 2, 8, 12, -5]

result = sorted(d, key=lambda x: abs(x))

ラムダ式は別の式(関数呼び出し)に埋め込める

 この例ではラムダ式をsorted関数呼び出しのkeyパラメーターに渡しています(実際には「key=abs」で済むのですが、ここでは例なのでご容赦を)。ラムダ式はこんな感じで使うものだということは覚えておきましょう。

 そういうわけで、代入文でラムダ式を変数に束縛しているこの表記は「NG!」です。

4:not ... isではなく、is not演算子を使う

 4つ目のコード片は次のようなものでした。

if val is not None:
    do_some_work(val)

is not演算子を使う

 これは変数valの値がNoneでないことを確認しています。実は、このコード片は次のようにも書けます。

if not val is None:
    do_some_work(val)

is演算子の結果を否定

 こちらはis演算子で変数valの値がNoneかどうかを調べて、その結果を否定することで結果的には上のコードと同じことをしています。しかし、PEP 8の「Programming Recommendations」では「not ... isではなく、is not演算子を使うこと。これらの式は機能的には同等だが、is not演算子の方が読みやすく、推奨される」とあります。

 確かに「val is not None」とまとめて書かれている方が「not val is None」の方がスッと頭に入ってくると思いませんか?

 そのような書き方をしているので、これは「OK!」です。

5:式を複数行に分けるときには二項演算子の前で改行する

 最後のコード片は以下のようなものでした。

res = (long_name_1 +
       long_long_name_2 +
       long_name_3 -
       long_long_name_4)

演算子の位置に注目

 少し説明が必要ですが、これは右辺の式全体をかっこ「()」で囲むことで、非明示的な行継続ができるようにしています(かっこがないと、バックスラッシュで明示的に行を継続させる必要があります)。その上で、問題のコード片では演算子を各変数の後に置いています。

 しかし、このコード片は次のように書くことがPEP 8の「Should a Line Break Before or After a Binary Operator?」で推奨されています。

res = (long_name_1
       + long_long_name_2
       + long_name_3
       - long_long_name_4)

演算子が同じ位置にあり、読みやすい

 最初のコードでは、変数名の長さがそれぞれに違うので、その後にある演算子の位置もバラバラです。これでは、何の演算をするのかを見分けるために、目の動きが余計に必要になるでしょう。書き直したコードでは変数名の長さに関係なく、演算子の位置は常に同じで、何をしたいかが一目瞭然です。

 そうした理由からPEP 8では後者の書き方が推奨されています。

 というわけで、問題文で示した「二項演算子を変数の後において、そこで改行する」ような書き方は「NG!」となります。


かわさき

 PEP 8は、Pythonコードを書く人にとっては最も一般的なコーディングスタイルガイドで、多くのプロジェクトで採用されており、従うべきとされる場面も多いでしょう。でも、その冒頭には「A Foolish Consistency is the Hobgoblin of Little Minds」(愚かな一貫性は小さな心の中の魔物)ともあります。つまり「一貫性にこだわりすぎるのはよくないよ」ということです。

 チームで開発しているのであれば、チームのコーディングスタイルに合わせればよいでしょうし、既存の資産を改修しているのであれば、既存のコードのスタイルに合わせる必要があります。そうしたところまで勘案しながら、一定のスタイルを保つようにしましょう。

 PEP 8については「Python入門」の「Pythonコーディングスタイルガイド」でも、より広範に取り上げています。興味のある方はそちらも読んでくれるとうれしいです。


「Pythonステップアップクイズ」のインデックス

Pythonステップアップクイズ

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。