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

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

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

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

Python

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

Q&A

解決済

4回答

895閲覧

Noneの判定をリファクタリングしたい

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

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

Python

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

0グッド

0クリップ

投稿2019/05/16 08:52

  • 関数Aがあります。引数aをもらいます。
  • 関数A内では、まず関数Bを呼び出します。

関数Bには引数としてaを与え、結果bもしくはNoneを返してもらいます。

  • 次に関数A内では、関数Cを呼び出します。

関数Cには関数B同様、引数としてbを与え、結果cもしくはNoneを返してもらいます。

  • 関数Dも関数Cと同じです。
  • 関数Aは関数Dの結果を返します。

上をコードにしてみたものの、同じような処理が書かれていて冗長に感じます。
どうすれば以下のコードを短くリファクタリングできますか?

python

1def A(a): 2 b = B(a) 3 if b is None: 4 return None 5 c = C(b) # bがNoneであるかもしれないことを想定していない 6 if c is None: 7 return None 8 d = D(c) 9 return d 10 11# 利用する 12y = A(x)

どこかでNoneが返ってきたらすぐにreturn Noneしたいという感じです。また、呼び出す関数側にNoneであるかもしれないことを考えさせていないわけですが、呼ぶ側と呼ばれる側のどちらでNoneに対する分岐を書くべきですか?

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

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

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

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

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

guest

回答4

0

呼出関数をリストに入れると簡潔に処理できると思います。

Python

1def A(a): 2 for f in [B,C,D]: 3 a = f(a) 4 if a is None: 5 break 6 return a

呼ぶ側と呼ばれる側のどちらでNoneに対する分岐を書くべきですか?

これはケースバイケースです。その関数にNoneが渡される可能性があれば分岐させます。
仕様上ありえないのであれば、分岐を書かずassertで済ませます。

投稿2019/05/16 09:07

編集2019/05/16 09:17
can110

総合スコア38352

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

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

0

何事もほどほどにというのは、プログラミングにも言えると思うのでベストな方法はケースバイケースな気はしますが、極端な場合(アプリケーションやモジュール内にこうした論理が多数必要というような場合)ちょっと凝ったことをしてみたくなることもあります。

python

1def callWhenNotNone(f, a): 2 return None if a is None else f(a) 3 4def A(a): 5 assert a is not None # AにNoneはわたってこないはずだがBに万一Noneが渡ると 6 # 危険ならこうしたガードを仕込みたいこともある 7 r = B(a) 8 r = callWhenNotNone(C, r) 9 return callWhenNotNone(D, r)

とか

python

1class GuardedValue: 2 def __init__(self, value): 3 self.value = value 4 5 def applySafe(self, f): 6 if value is None: 7 self.value 8 else: 9 self.value = f(self.value) 10 return self 11 12 def apply(self, f): 13 assert self.value is not None 14 self.value = f(self.value) 15 return self 16 17def A(a): 18 gv = GuardedValue(a) 19 return gv.apply(B).applySafe(C).applySafe(D).value

Swift言語などにあるNull安全機能をちょっとまねてみたというコードです。

ただ下手にこういうことをやると却って可読性が下がったり、必要性の薄い関数やクラスの設計にかけた時間に対して大して得るものが少なかったりと、自己満足に終わる危険が大きいかも知れません。

こうした方法は頭の体操的な意味が多少あるとは思いますが、平易かつ適度な簡潔さで書くという本来的な意味で、多くの場合他の方の回答の方が適切な気がします。

そもそもPythonでこういう配慮をしたくなる大き目のアプリケーションって書くことがあるのか・・・小さめのもの(せいぜい数百行くらい)しか書いたことのない自分にはそのあたりのはっきりとした考えがありません。

呼ぶ側と呼ばれる側のどちらでNoneに対する分岐を書くべきですか?

can110さん回答に同意です。ケースバイケース。Noneに対する分岐も「その関数の機能の一つ」です。呼ばれる側にその機能が本質的に必要なら呼ばれる方に書くべきですしそうでないなら書くべきでないでしょう。

例えば汎用的な初等関数math.powにNoneチェックを入れるべきでしょうか?NOだと思います。この関数の機能は「与えた数値に対して計算すること」だけであって数値以外を渡しても何かの値を返すという機能は不必要と思います。

一方引数にNoneを渡したとき特定の規定値を仮定するといった明確な意義があるならNoneチェックをする意味があるでしょう。例えばNoneを許さない関数を呼び出す必要があり、かつその引数がNoneとなるケースを想定せねばならないAはそういう類の関数と言えましょう。

投稿2019/05/16 12:30

KSwordOfHaste

総合スコア18404

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

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

0

ベストアンサー

None 以外のケースの考慮がザルなのであまりおすすめできませんが…。

python

1def A(a): 2 b = B(a) 3 c = b and C(b) 4 d = c and D(c) 5 return d

きちんと None を判定するとこうなるかな。

python

1def A(a): 2 b = B(a) 3 c = C(b) if b is not None else None 4 d = D(c) if c is not None else None 5 return d

投稿2019/05/16 10:50

mather

総合スコア6762

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

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

mather

2019/05/16 11:14

リファクタリングという意味では、各関数がNoneを受け付けるかどうかは定義次第です。 ある関数が引数にNoneも受け付けるべき(Noneの場合の処理がある、またはオプションの値が指定されていないというケースを表現するためにNoneに意味がある)かどうかは関数単体の視点で判断したほうがいいと思います。 周りの使用方法に合わせるということも必要なケースはあると思うのですが、できる限りそのような事情は呼び出し元でコントロールしたほうがいいと思います。
KSwordOfHaste

2019/05/16 12:46

「関数単体の視点で判断」に自分も賛成です。 matherさんの上のコメントに気づかずに自分の回答後半を書いたのですが、蛇足だったかもです。
guest

0

コードをスッキリさせるなら以下でどうでしょう。
B, C, D関数の冒頭でそれぞれ入力値がNoneである場合、即return Noneするよう追記してください

python

1def A(a): 2 return D(C(B(a))) 3 4# 利用する 5y = A(x)

投稿2019/05/16 09:08

moonphase

総合スコア6621

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問