14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

この記事誰得? 私しか得しないニッチな技術で記事投稿!

【Python】pass と Ellipsis の使い分けを検討する

Last updated at Posted at 2022-09-20

はじめに

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自体には強制力はありません。
大事なのは、チームや個人がこのような一貫した考え方を持って開発できるかにあると思います。
本稿がそういった考え方の一助になると嬉しいです。

参考文献

  1. https://docs.python.org/ja/3/reference/simple_stmts.html#the-pass-statement

  2. https://docs.python.org/ja/3/library/constants.html#Ellipsis

  3. https://tuxtimo.me/posts/2021/11/05/python-pass-vs.-ellipsis/

14
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?