質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2786閲覧

Optionalの比較

yonchome

総合スコア41

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/12/17 15:44

編集2020/12/19 07:46

pythonのOptional型で以下の場合castが必要です。

python

1a: Optional[int] = 0 2 3def add_one(x: int) -> int: 4 return x + 1 5 6a = cast(int, a) 7add_one(a)

結果は1

python

1a: Optional[int] = 0 2b: int = 0 3 4assert a == b

結果はTrue

一方で比較の時にはcastが不要です

比較する時にcastが必要になるケースはあるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2020/12/17 23:31 編集

* 一切使われてないadd_oneは何でしょう? * コードはコードブロックの中に書いてください。インデントが消えたりするので特にPythonは意味がわからなくなります
quickquip

2020/12/17 23:31

コードの一部が欠けていませんか? > castが必要です なにのために「castが必要」と言っていますか? IDEやlintの警告解消だと思いますが、そのあたり「なんのツールか」「どこがどんな警告になるか」を追記するといいかと思います。 コードはコードとして読めるようにしてください。 https://teratail.com/help#about-markdown https://teratail.com/help/question-tips#questionTips3-5-1 を参考に。コードを選択して <code>ボタンがいいでしょう。
yonchome

2020/12/19 07:46

変更しました
quickquip

2020/12/19 11:07 編集

> castが必要です なぜ? なにに必要?
yonchome

2020/12/20 05:01

https://qiita.com/kenta1984/items/169e5dcbdbf0b4c8af27 上記の記事のケースで ypeError: '<=' not supported between instances of 'str' and 'int' というエラーメッセージが出ています。 これをOptional[int]とintで行う場合はエラーなく動きます。 Optionalの場合はこのcastをする必要はないのかという質問でした????‍♂️
quickquip

2020/12/20 07:28

(情報をこの欄に書かれても困りますので質問を編集してください) 14:01 のコメントの主旨は、strとintを比較するとエラーになるが、Optional[int]とintの比較をするとエラーにならない。「castをする **必要がない** のはなぜか?」ということかと思います。(それは質問として理解できます) 私が質問に書いて欲しいと思ったのは、「質問の上のソースでcastが **必要だと思っている** のはなぜか?」でした。castは"何もしない関数"なので、実行時に必要になることは決してないはずなのです。 もしかしたら、上のソースは不要で、下のソースだけを書いてこうするとエラーだがこうするとエラーにならないがこれはなぜか? と聞けばよかったのかもしれませんが、とはいえ上のソースでなぜ必要だと思っているのかはどうしても気になりますね。 それはつまり、cast関数を誤解しているのだろうと想像できるからですが、それがハッキリしないと **何を回答していいのか** が明らかではないです。
guest

回答1

0

ベストアンサー

質問のポイントがわからないのでだらだらと書きます。

Optional はPython上の型ではなく、アノテーションとして書ける型ヒントでしかありません。
Optional型の値(インスタンス)は存在しないので、「Optional型の値とint型の値を比較する」というようなことは、実行時には起こりません。
型チェッカーが検査するときに「Optional型の式とint型の式を比較する」ということは起こりますが、これは問題がありません演算子によっては型チェックの結果として警告されることがありえます。

そもそも、比較に限らず、実行時には型ヒントは無視されるので、型ヒントが原因で何かが起こったり起こらなかったりするということはありません。(型ヒント自体がエラーになることはあっても)


typing.cast何もしない関数ですから、"castが必要です"などということはありえません

https://docs.python.org/ja/3/library/typing.html#typing.cast

この関数は値を変更せずに返します。

cast関数が実行結果に影響を及ぼすことは起こりません。(引数の評価がエラーになることはあっても)


Optional[int]Union[int, None]の略記です。

https://docs.python.org/ja/3/library/typing.html#typing.Union

Optional[X] を Union[X, None] の略記として利用することが出来ます。

また型ヒントに書くNoneは、type(None)の略記です。
type(None)はNoneTypeというクラスを返しますが、Pythonの標準ライブラリはこのクラスを指す名前を提供しません。Noneが唯一のインスタンスで、かつNone以外のインスタンスを生成することは不可能なので型ヒントにNoneを使っても不都合がないのです)

https://docs.python.org/ja/3/library/typing.html#type-aliases

型ヒントとしての None は特別なケースであり、 type(None) によって置き換えられます。

Optional[int]は、Union[int, type(None)]と同義で、その意味は、

型ヒントを付けた対象がint型の値であるかNoneType型の値(要はNone)である

ということで、そのことを型チェッカーに示すために使います。

Optional[int]という型ヒントがついた式と、intという型ヒントがついた式を比較演算子で比較した時、(型ヒントに記載したことが正しく守られていれば)実行時に起きる事象は

  1. int型の値とint型の値の比較
  2. int型の値とNoneの比較

の2つということになります。


後者のケースだと、比較演算子が==なら必ず偽です。!=なら必ず真です。
<, >, <=, >= の場合TypeError: '<' not supported between instances of 'int' and 'NoneType' が発生します。

要は、

==(や!=)は、 まったく関連のない型同士の場合でもis(やis not)を用いたオブジェクトの同一性でチェックされるので動きます。
それ以外の <, >, <=, >= は、まったく関連がなく比較が実装されていない型同士ではTypeErrorが発生します。

ということです。
これには型ヒントやcastはまったく関係がありません

(誤解が生じるかもしれないので追記)
"これには型ヒントやcastはまったく関係がありません"と書いたのは"実行時に型ヒントやcastが関係して挙動が変わることはありません"という意味です。
型チェッカーが検査するときは、当然ですが、型ヒントやcastが関係してきます。


(追記)

そもそも

python

1a: Optional[int] 2 3... 4 5a = cast(int, a)

は矛盾があります。上では"aはint型の値かNone"とヒントを示しているのに対して、下では"aはNoneではありえない"としているのですから。

型チェッカーの検査で下のcastが必要になるとしたら、省略している ... の箇所にreturn文やsys.exitなどがあってaがNoneである可能性が省かれていて、かつプログラマはそうと確信しているのに型チェッカはそうと認識できないケースです。

それは2つの可能性があります。
型チェッカーの機能が不十分で"aがNoneである可能性が省かれている"ことが認識できない

型チェッカーに伝わるような書き方をプログラマがサボっている

です。

後者であればcast関数を書くことよりも、型チェッカーに分かるように伝わるように書くことに注力するべきでしょう。

前者であっても

python

1assert a is not None

python

1assert isinstance(a, int)

とチェックする方が正着な気がします。実行時チェックが入るので動作としてはcastより時間がかかるかもしれませんが(本当にはわかりません)意味的なわかりやすさを優先する方がいいかと思います。

(このあたりの「わかりやすさ」は主観になるかとは思いますが)

投稿2020/12/21 13:34

編集2020/12/22 04:09
quickquip

総合スコア11235

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問