これに関するあなたの直感は正しいです、これを行うより良い方法があります:モナド。
モナドとは何ですか?
モナドは(Wikipediaを換言すると)連鎖メカニズムを隠しつつ操作を連鎖する方法です。あなたの場合、連鎖メカニズムはネストされたif
sです。それを隠すと、コードの匂いがずっと良くなります。
それを行うモナドがいくつかあり( "Maybe"および "Either")、幸運なことに、それらは本当に素晴らしいpythonモナドライブラリの一部です!
彼らがあなたのコードのためにできること
以下は、「Either」モナド(リンクされたライブラリの「Failable」)を使用した例です。関数は、発生した内容に応じてSuccessまたはFailureを返すことができます。
import os
class DoSomething(object):
def remove_file(self, filename):
try:
os.remove(filename)
return Success(None)
except OSError:
return Failure("There was an OS Error.")
@do(Failable)
def process_file(self, filename):
do_something()
yield remove_file(filename)
do_something_else()
mreturn(Success("All ok."))
さて、これは現在のものとあまり変わらないかもしれませんが、失敗につながる可能性のある操作がさらにある場合の状況を考えてみましょう。
def action_that_might_fail_and_returns_something(self):
# get some random value between 0 and 1 here
if value < 0.5:
return Success(value)
else:
return Failure("Bad value! Bad! Go to your room!")
@do(Failable)
def process_file(self, filename):
do_something()
yield remove_file(filename)
yield action_that_might_fail(somearg)
yield another_action_that_might_fail(someotherarg)
some_val = yield action_that_might_fail_and_returns_something()
yield something_that_used_the_return_value(some_val)
do_something_else()
mreturn(Success("All ok."))
関数yield
内の各sで、process_file
関数呼び出しがFailureを返した場合、process_file
関数は終了します。はその時点で残りの部分を続行して返すのではなく、失敗した関数からFailure値を返しますSuccess("All ok.")
さて、入れ子で上記を行うことを想像してください if
sで!(戻り値をどのように処理しますか?)
結論
モナドはいいです:)
ノート:
私はPythonプログラマーではありません-プロジェクトの自動化のために忍者のスクリプトで上記にリンクされたモナドライブラリを使用しました。ただし、一般的には、例外を使用するのが一般的で好ましい方法です。
IIRCは、リンク先のページのlibスクリプトにタイプミスがありますが、ATMの場所は忘れています。覚えたら更新します。私は自分のバージョンをページのものと比較しました:def failable_monad_examle():
-> def failable_monad_example():
- p
in example
がありませんでした。
Failable装飾関数(などprocess_file
)の結果を取得するには、結果をaにキャプチャし、それを取得するためにa variable
を実行するvariable.value
必要があります。