2020年6月14日日曜日

4: mypyの厳格なオプショナルチェック機能を使うべきか使わざるべきか

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

実のところ、当機能はかなり頭が悪い。ここには、苛立たしさのあまり、この機能を使う価値があるかを疑わせるようないくつかのケースが紹介されています。

話題


About: Pythonプログラミング言語
About: mypy

この記事の目次


開始コンテキスト


  • 読者は、Pythonの基本的知識を持っている。
  • 読者は、mypyの基本的知識を持っている。

ターゲットコンテキスト



  • 読者は、mypyの厳格なオプショナルチェック機能の頭の悪さのいくつかのケースおよびそれらの解決策を知る。

オリエンテーション


そもそも、なぜmypyまたはそれに類したものを使用すべきかについての記事があります。


本体


1: 意図は良いのであるが . . .


Hypothesizer 7
mypyの厳格なオプショナルチェック機能を私はオンのままにしておいた(デフォルトでオンになっているとおりに)、コンセプト上は、それは助けになると思われるから。...実際、nullポインター例外(Python変数はポインターである、私が繰り返し言明するとおり)が静的に防げるのであれば、それは良いことだろう。

しかしながら、その意図を実現化したものは頭が悪すぎて、おりおり鬱陶しいことにならざるをえず、最近、私は新しいタイプの頭の悪さに遭遇した(次セクションで見よう)。

回避策は確かにあるが、そのようなきたない回避策を投入するだけの価値がその機能にあるのか否か、を私は思い惑い始めた。


2: リストの、変数でインデックス指定されたオプショナルな要素についての問題


Hypothesizer 7
以下のコードは、問題である、とmypyによって判定される。

@Python ソースコード
		l_listOfOptionals: List [Optional [str]] = ["AAA", "BBB"]
		l_index: int = 0
		if l_listOfOptionals [l_index] is not None:
			print ("### " + l_listOfOptionals [l_index])

エラーメッセージおよびその注釈は、以下のとおりだ: 「error: Unsupported operand types for + ("str" and "None")」および「note: Right operand is of type "Optional[str]"」。

ふーむ、そこの非'None'チェックがそのエラーを防ぐはずだと思っていたのだが...

以下のように'assert'を使ってもうまくいかない。

@Python ソースコード
		assert l_listOfOptionals [l_index] is not None
		print ("### " + l_listOfOptionals [l_index])

私のコードが問題か?mypyが問題だと私なら言うだろう。

シンプルなオプショナル変数であれば、以下でうまくいく。

@Python ソースコード
		l_optionalString: Optional [str] = "AAA"
		if l_optionalString is not None:
			print ("### " + l_optionalString)

問題は、リストのオプショナル要素についてであるらしい...

しかし、以下は良い。

@Python ソースコード
		if l_listOfOptionals [0] is not None:
			print ("### " + l_listOfOptionals [0])

リテラルでインデックス指定された要素のチェックはうまくいくようだ。

したがって、より正確に言うと、問題は、リストの、変数でインデックス指定されたオプショナル要素についてであるらしい。インデックス指定している変数が、非'None'チェックとエラー判定された行の間で変更されていないことをmypyは認識できないようだ、それらの間には行は全然ないにもかかわらず...

それでは、私はどうすればよいのか?...明らかに、以下のような回避策は存在する。

@Python ソースコード
		l_listElement: Optional [str]
		l_listElement = l_listOfOptionals [l_index]
		if l_listElement is not None:
			print ("### " + l_listElement)

それは確かにうまくいくが、私は本当にそんなことをさせられないといけないのか?

別の解決策は、いっそのこと、厳格なオプショナルチェック機能をオフにすることだ。

その機能は、mypyコマンドに'--no-strict-optional'スイッチを追加することでオフにできる。


3: 頭の悪さのもっとあからさまなケース


Hypothesizer 7
そうした特殊なケースを挙げるまでもなく(もしも、それが本当に特殊だとして)、以下のコードにおいて、変数が'None'でないことを、mypyは認識できない。

@Python ソースコード
		l_optionalString: Optional [str] = "AAA"
		print ("### " + l_optionalString)

...したがって、私は以下のようにしなければならない。

@Python ソースコード
		l_optionalString: Optional [str] = "AAA"
		if l_optionalString is not None:)
			print ("### " + l_optionalString))

それって馬鹿げていないだろうか?変数が'None'でないことを、それに’AAA'があからさまに入れられた直後にチェックしなければならないのだろうか?


4: 当機能を使うべきか使わざるべきか


Hypothesizer 7
当機能の頭が悪いのは、私の気のせいではありませんよね?

...えーと、私はその機能をオフにするつもりです、少なくとも、その機能の頭の悪さが減ずるまでは。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>