はじめに
Pythonを書く上際に、処理を省略・仮実装・抽象化する場合があると思います。
その際に、pass
文を使うべきかEllipsis
を使うべきか検討したいと思います。
※ 本稿は、部内のLTでプレゼンされる内容の忘備録です。
環境
- Python 3.10.6
結論
下記のように使い分けるのが良さそう
pass
文: 「何も実行しないこと」がその処理として本質的な場合に利用する。
Ellipsis
: 「未実装な処理」や「コンテナデータ型の拡張表現」として利用する。
pass
誰もが知っているおなじみのpass
文です。
pass はヌル操作 (null operation) です --- pass が実行されても、何も起きません。
pass は、構文法的には文が必要だが、コードとしては何も実行したくない場合のプレースホルダとして有用です。1
公式ドキュメント曰く、下記のように未実装関数の仮置きに使えます。
def hoge():
pass
また、処理内で何もしないことを明記したい場合にも活躍します。
try:
hoge + 2
except TypeError:
pass
if hoge == 2:
return hoge
elif hoge == 3:
pass
else:
return 1
Ellipsis
そもそもEllipsis
ってなんですか?みたいな人が多数いると思うのですが、...
のことです。
print(...)
>>> Ellipsis
これを見ても???な方がいるかもしれないので公式ドキュメントの説明を翻訳します。
省略記号リテラル「...」と同じ。主にユーザー定義のコンテナデータ型の拡張スライス構文と組み合わせて使用される特別な値です。
Ellipsisは、types.EllipsisType型の唯一のインスタンスです。2
つまり、省略を表すオブジェクトです。passと異なり、文ではなく単なる値です。
ドキュメントでは、コンテナデータ型の拡張スライス文で使用されると書いてありますが、主にNumpy
のことです。
import numpy as np
arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(arr[..., 0])
>>> [[1 3]
>>> [5 7]]
ほかにも、可変長タプルの型アノテーションを書く際に利用します。
def hoge(count) -> tuple[int, ...]:
return (i for i in range(count))
a, b, c = hoge(3)
print(a, b, c)
>>> 0 1 2
pass と Ellipsis の使い分け
それぞれの公式ドキュメントの見解とよくある使い方を見てきました。
そこでですが、下記のような表記はどう思いますか?
try:
hoge + 2
except TypeError:
...
「違和感を感じる」、「気持ち悪い」、「どっちでも分かる」みたいな否定的な感じでしょうか?
もちろん、Ellipsis
自身は何もしないので、pass
文と同等のヌル操作として捉えることが出来ます。
ここで公式ドキュメントの話を振り返ってみると、それぞれ以下のような意味合いの違いを感じます。
(一旦公式ドキュメントの推奨している利用方法は無視し、説明を元に検討します)
-
pass
: 操作としてのイメージ -
Ellipsis
: 何かを省略したいイメージ
そのため、下記ようなコメントアウトがあるとありだと感じます。
try:
hoge + 2
except TypeError:
# TODO 後で型エラーについての処理を記載します。
...
この書き方であれば「何か省略されているので今後実装される」ように見えます。
また、確定した処理の場合はpass
を使って「何も実行しないことが操作である」ように見せた方が分かりやすいと感じます。
try:
hoge + 2
except TypeError:
pass
未実装関数・クラスにも同様のことが言えます。
# 未実装関数
def hoge():
...
# 未実装class
def Hoge:
...
# おまけ、変数の仮置きにも使えます
hoge: int = ...
では、インターフェースを作成する時は、pass, Ellipsisのどちらを使いますか?
from typing import Protocol
class Animal(Protocol)
def bark(self) -> str:
...
Ellipsis
ですね。理由は、将来的に実装クラスで省略された処理が実装されるからです。
こう見ると、pass
文は本当に何もしないとき以外はあまり使わない方が良いかもしれませんね。
※ 上記の検討は「Python Pass vs. Ellipsis3」という記事でも題材として扱われていました。こちらも一読おすすめです。
おわりに
結局のところ、こういった考え方があるといっただけでPython
自体には強制力はありません。
大事なのは、チームや個人がこのような一貫した考え方を持って開発できるかにあると思います。
本稿がそういった考え方の一助になると嬉しいです。