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

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

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

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

Q&A

解決済

2回答

1688閲覧

例外処理は詳細に指定しなければならないのでしょうか

ruuuu

総合スコア176

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

0グッド

2クリップ

投稿2021/12/13 01:08

編集2021/12/13 02:41

pythonのコーディング規約について、少々お聞きしたいことがあります
Djangoでの開発を行っている際に、try except構文にて、以下のような形で詳細な例外を指定しなかった場合に、コーディング規約であるpep8の警告がエディターで表示されてしまいました。

try: user.save() except: return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

しかし、例えばですが、例外の種類によって、例外が発生した場合の処理を分ける必要がない場合は全ての例外をキャッチする形でも問題ないように思えます。
現状、警告を無視しても良いのか、どう対処するべきかいまいち分からない状況な為、ご助言の程頂きたいです。
よろしくお願いします

※except内の処理は誤解を生んでしまっていたので、変更しました

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

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

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

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

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

1T2R3M4

2021/12/13 01:12

ruuuuさんのコーディングルールはどうなっているのですか。
ruuuu

2021/12/13 01:55

基本的には、PEP8に準拠したルールで開発を進めています
guest

回答2

0

ベストアンサー

maisumakunさんの回答の補足ですが、その警告の意図は、
そういった例外の大域捕捉がやりたいなら

python

1while True: 2 try: 3 print(int(input()) * 10) 4 except: 5 pass

じゃなくて

python

1while True: 2 try: 3 print(int(input()) * 10) 4 except Exception: 5 pass

except Exception:で書きなさい、というものです。
実行して動作を比べてみてください。上のコードをCtrl+Cで終了させようとする時に"生のexcept"が意味するところが判ると思います。

警告はそれで消えると思います。(チェッカが分からないので断言はできませんが)


それはそれとして質問の本筋です。

例えばtweepyの例でバージョン4.0からそれまでのTweepErrorを、TweepyExceptionとHTTPExceptionに分離しました。
https://docs.tweepy.org/en/stable/changelog.html#version-4-0-0

Replace TweepError with TweepyException (5c39cd1) and HTTPException (#599)

取り扱えないイメージを渡したなどで差し戻された時に発生するのがTweepyException
Twitter APIから200番台じゃない異常ステータスが返ってきた時に発生するのがHTTPException
と分けられたわけです。

python

1try: 2 api.some_api(**some_args) 3except TweepError: 4 print('something wrong')

と書いていた人は修正する手間が発生しました。

python

1try: 2 api.some_api(some_args) 3except Exception: 4 print('something wrong')

と書いていた人は修正せずに済みました。

後者の方が幸せでしたね、という結論になりますか? という話です。

TweepErrorをTweepyExceptionとHTTPExceptionに分離した意図は、
例外が発生する状況を精査すると対処しなければならないことが異なるケースを同じ例外にしていた。これはよくない
ということだと思います。

TweepErrorとは別にHTTPExceptionを追加するだけだと、既存のコードはそのまま動くかもしれないけれど、それでは「対処しなければならないことが異なる」ことに対して対処するチャンスを奪うわけです。
その時におこなわれた議論を調べたわけではなくてこれはただの想像ですが、TweepErrorからTweepyExceptionにすることで意図を明確化したんだろうと思ってます。

この時

python

1try: 2 api.some_api(some_args) 3except Exception: 4 print('something wrong')

としていた人はそのまま動いてしまうため、TweepyExceptionとHTTPExceptionに分離した意図に気づけないです。


業務寄りの開発ではより切実でしょう。
ある例外に対する対処コードを変更しなければならないとなった時、修正するべき箇所がどこにあるかを探索するのにぜんぶをexcept Exception:で補足していたら、どう探せばいいんでしょう??

投稿2021/12/13 02:40

編集2021/12/13 03:09
quickquip

総合スコア11235

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

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

ruuuu

2021/12/13 11:35 編集

ご回答ありがとうございます。 >実行して動作を比べてみてください。上のコードをCtrl+Cで終了させようとする時に"生のexcept"が意味するところが判ると思います。 こちら、ご提示頂きました2つの例を実行してみたのですが、「 except: 」を使用したケースで、Ctrl+Cによる強制終了が出来ないということに驚きました。 こちらは、プログラムとは無関係の所で発生してしまっているエラーですし、このエラーを補足してしまうというのは、どうなんだろうというのは確かにありますね... >ある例外に対する対処コードを変更しなければならないとなった時、修正するべき箇所がどこにあるかを探索するのにぜんぶをexcept Exception:で補足していたら、どう探せばいいんでしょう?? こちら、まさにご指摘の通りかと思います。 となりますと、どの例外が発生した場合でも500エラーの旨をレスポンスとして返すといったことがしたかった場合、以下のようにする形が望ましいでしょうか。 try: user.save() except ZeroDivisionError as e: logger.debug('ZeroDivisionError',e) return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) except TypeError as e: logger.debug('TypeError',e) return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) except Exception as e: logger.debug('Exception ',e) return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) こちら、想定される例外を一通り記述し、最後に想定外の例外が発生した場合の処理を記載する、といった形で記載してみました
quickquip

2021/12/13 11:59

すみません。こちらそのあたりを考えて常に選択していく必要があります、業務側に寄れば寄るほどちゃんとしないといけないです、ぐらいの趣旨です。 Djangoだと本体側で捕捉されるので自分で雑に捕捉する必要を感じなくて、起こりえると分かっていて対処する必要があると思っているものだけを列挙すればよいと思います。(質的に違いがでない)
quickquip

2021/12/13 12:02

except Exception: じゃなく except: をわざわざ選ぶ理由は基本ないと思います。
ruuuu

2021/12/13 12:18

ご返信、ありがとうございます。 > Djangoだと本体側で捕捉されるので自分で雑に捕捉する必要を感じなくて、起こりえると分かっていて対処する必要があると思っているものだけを列挙すればよいと思います。(質的に違いがでない) こちら、細かい部分で申し訳ないのですが、「本体側で捕捉される」とは具体的にはどういった意味を指しておられましたでしょうか...?
quickquip

2021/12/13 12:59

Djangoだとdebugモードなら起きた例外の詳細が表示されるし、debugモードじゃないなら例外の詳細は隠蔽されて500番ステータスが返りますよね。 設定をしっかりすればログのコントロールもできるはずでは、と思いましたし。
ruuuu

2021/12/13 14:47

ありがとうございます 自分ちょっとDjangoの仕様の部分、分かっていない部分がありました。 >Djangoだとdebugモードなら起きた例外の詳細が表示されるし、debugモードじゃないなら例外の詳細は隠蔽されて500番ステータスが返りますよね。 こちらの部分調べてみたいと思います。
guest

0

例外の種類によって、例外が発生した場合の処理を分ける必要がない場合は全ての例外をキャッチする形でも問題ないように思えます。

そうも行かないこともありえます。

生の except:SystemExitKeyboardInterrupt 例外もキャッチしてしまうため、プログラムを Control-C で中断することが難しくなりますし、他の問題をもみ消してしまうかもしれません。(pep8和訳より)

書き捨てのプログラムならともかく、Djangoで組むような一定の規模を持ったものでは、基本的に避けるべきだと考えます。

投稿2021/12/13 01:16

maisumakun

総合スコア146018

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

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

maisumakun

2021/12/13 01:18 編集

> 例外の種類によって、例外が発生した場合の処理を分ける必要がない場合 「分ける必要がない場合」に「userモデル内にバグを作り込んでしまっていた場合」まで含めてしまう(そして起きた例外をどこにも伝えないコードを書いている)と、そもそもコードのバグに気づけない場合が出てくるなど、デバッグが困難となります。
ruuuu

2021/12/13 01:53 編集

ご回答ありがとうございます。 >そもそもコードのバグに気づけない場合が出てくるなど、デバッグが困難となります。 こちら、ご指摘の通りかと思います しかし、指定していない種類の例外が発生した場合に、該当の処理を行うことが出来なくなってしまう、ということは考えられませんでしょうか。 想定されるエラーを全て指定できれば良いかと思うのですが、exceptにて指定していないエラーが発生した場合、何が起こったか把握出来ず、アプリケーションが想定外の動作を起こしてしまうこともあるかと思います
maisumakun

2021/12/13 01:56 編集

> 想定されるエラーを全て指定できれば良いかと思うのですが、想定外のエラーが発生した場合、何が起こったか把握出来ず、アプリケーションが想定外の動作を起こしてしまうのではないか むやみに例外を受け取って「ok」なんてしてしまうほうが「想定外の動作」に陥る危険が大きいです。例外を投げっぱなしにした場合、Djangoサイドに最低限の処理(「サーバエラーです」と表示するなど)が組み込んであります。 > 指定していない種類の例外が発生した場合に、該当の処理を行うことが出来なくなってしまう 無視できるとはっきりしている例外ではなければ、できなくなってしかるべきです。例外が起きているのに、何も考えず進ませるほうが恐ろしいことです。
ruuuu

2021/12/13 02:06 編集

ご返信ありがとうございます。 現状、Django側をAPIとして使用しているのですが、try-exceptには、指定した例外以外のエラーが発生した場合に、何かエラーが発生している旨を返すレスポンスいった構文はなかったと思います その為、何かエラーが発生している旨をフロント側へ返すレスポンスを作成したいと考えているのですが、「Djangoサイドに最低限の処理(「サーバエラーです」と表示するなど)が組み込んであります。」 こちらに関しまして、詳しく教えて頂くことはできませんでしょうか
maisumakun

2021/12/13 02:04

「Django 例外」などで調べてみましょう。
ruuuu

2021/12/13 02:11 編集

例外について、調べてみます。 重ね重ねになってしまうのですが、つまり例外に関しましては、exceptで指定した例外以外のエラーが発生した場合、Django側で設定したレスポンスを必ず返すのが望ましいということでしょうか...?
maisumakun

2021/12/13 02:13

> exceptで指定した例外以外のエラーが発生した場合、Django側で設定したレスポンスを必ず返すのが望ましいということでしょうか...? 「無視して続行する」のは論外ですが、そうでないとしてどのような実装を行いたいのですか? (デフォルトで間に合うのならそのまま使うのが楽です)
ruuuu

2021/12/13 02:16

> 「無視して続行する」のは論外ですが、そうでないとしてどのような実装を行いたいのですか? 例えば、現状、どの例外が発生した場合でも、以下のように処理を行うように実装しています。 return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) しかし、現状、処理を特段分けたい場合でもない為、500エラーが起きている旨をフロント側へ知らせるように実装できれば良いと考えています
maisumakun

2021/12/13 02:19

> 以下のように処理を行うように実装しています。 それを先に言ってほしかったです。「print('ok')」なんて書いていたので、「無視して続行する」ことを前提に書いているものだと思いこんでいました。
maisumakun

2021/12/13 02:21 編集

きちんとログを吐けば、「全部500を返す」という実装は特に問題があるものではありません。 (pep-8の中にも「生の 'except' を使う場合」の1つとして「例外ハンドラが traceback を出力するかロギングする場合」が挙げられています)
ruuuu

2021/12/13 02:23 編集

>それを先に言ってほしかったです。「print('ok')」なんて書いていたので、「無視して続行する」ことを前提に書いているものだと思いこんでいました 申し訳ないです。 本文の方、修正しました。 >きちんとログを吐けば、「全部500を返す」という実装は特に問題があるものではありません。 となりますと、「 except: 」で全ての例外を受ける形でも問題はないということでしょうか...?
maisumakun

2021/12/13 02:24

> except: 」で全ての例外を受ける形でも問題はないということでしょうか...? はい、サーバサイドで汎用的な例外処理を行うのは悪くない実装です。
ruuuu

2021/12/13 02:24

そうでした。 ログの設定も必要ですよね... ちょっとここら辺はまた調べつつやっていきたいと思います。
ruuuu

2021/12/13 02:27

>はい、サーバサイドで汎用的な例外処理を行うのは悪くない実装です。 重ね重ね、ありがとうございます! そうなりますと、コーディング規約に関しましても、PEP8のルールを守りつつも、完璧にこだわりすぎる必要もないということですね... 警告が出ていたので、どうしようかと迷っていたのですが、とても参考になりました。
maisumakun

2021/12/13 02:29

> コーディング規約に関しましても、PEP8のルールを守りつつも、完璧にこだわりすぎる必要もないということですね... すでに書きましたように、PEP8自体に「生の 'except' を使う場合」というのが書かれています。
ruuuu

2021/12/13 02:33

あれ、自分また勘違いしているかもしれないのですが、「生の 'except' 」 = 「汎用的な例外処理」といった意味ではありませんでしたでしょうか...?
maisumakun

2021/12/13 02:34

そうですね。 ただ、「expect: だけを使うのに適当なのか」を機械的に判定できないので、問答無用に警告が出されることはありえます。
ruuuu

2021/12/13 02:36

ありがとうございます! >ただ、「expect: だけを使うのに適当なのか」を機械的に判定できないので、問答無用に警告が出されることはありえます。 こちら、納得できました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問