6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python: 関数のデフォルト引数にはOptional指定は不要

Last updated at Posted at 2021-03-12

言われてみれば当たり前なんですけど、typing使い始めたばかりのころのコードで勘違いをしていたのを発見したのでメモ。
バグの原因になる可能性がありました。

参考:typing --- 型ヒントのサポート — Python 3.9.2 ドキュメント#typing.Optional

検証:Visual Studio Code, Pylance, Python 3.8.5

簡潔に

Optional =「Nullable(Noneable)」だということ。
引数が英語で言う「optional」だという意味ではない。

正しい例

以下のように、引数rightにデフォルト引数を設定することを考えます。

correct.py
# 引数2個を加算して返す関数(正しい例)
def add_num(left: int, right: int = 0) -> int:
    added = left + right
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# これはおかしいので警告が出るべき
wrong = add_num(9, None)  # Type "None" cannot be assigned to type "int"

最後の行で関数add_numに不適切な引数を渡しているので、以下のように警告が表示されます。

typingのエラー文(一部)
  Type "None" cannot be assigned to type "int"

間違った例

「デフォルト引数は省略可能だから、optionalだよね」と勘違いをして以下のようにOptional指定をしてしまっていました。

wrong.py
from typing import Optional

# 引数2個を加算して返す関数(typingの指定がおかしい)
def add_num(left: int, right: Optional[int] = 0) -> int:
    added = left + right
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# これは本来おかしいのだが…
wrong = add_num(9, None)  # 警告は出ない

Optional指定はあくまでも Noneを渡すことができる ということを示すものなので、このような場合はOptional指定は不適切です。

今回の例の場合は、コーディングの段階では警告は表示されません。
実行時にintNoneを加算しようとして例外が発生することになります。

⇒ 追記:現在(Python3.11)はintint | Noneとの加算はできない旨のエラーメッセージが出ます。当時は出てなかったはず。

不適切ではない例

正しいOptional指定の使い方はこんな感じ。
(あくまでもOptionalの使い方の話です。なんでそこでNoneを渡すんだとかいうツッコミは無しで…)

correct_optional.py
from typing import Optional

# 引数2個を加算して返す関数(rightにNone指定が可能)
def add_num(left: int, right: Optional[int] = 0) -> int:
    right_int: int = 0  # intであることが確実な変数
    if right is not None:
        right_int = right

    added = left + right_int
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# 関数の仕様として意図した使い方
not_wrong = add_num(9, None)  # もちろん警告は出ない

不適切ではない例その2

Python4.0でint | None的な書き方ができるようになるらしいですが、
Python3.10でint | None的な書き方ができるようになりました。
参考:組み込み型 — Python 3.11.0b5 ドキュメント#Union Type

correct_optional_2.py
from typing import Optional

# 引数2個を加算して返す関数(rightにNone指定が可能)
def add_num(left: int, right: int | None = 0) -> int:
    right_int: int = 0  # intであることが確実な変数
    if right is not None:
        right_int = right

    added = left + right_int
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# 関数の仕様として意図した使い方
not_wrong = add_num(9, None)  # もちろん警告は出ない

Noneを引数で渡す!ということが明確になって良いですね。

int | None的な書き方ができる環境なら、Optionalなんてわかりにくいものは使っちゃダメです。

6
3
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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?