2016-07-22 3 views
1

だから、私は賢くて、DRYという共通のコードをたくさんの類似の機能から削除し、それらをヘルパー機能にまとめて1つの場所に定義することで、 (GitHub diffを参照してください)そうすれば、それらはすべて一箇所から変更できます。 (another GitHub diffを参照)ヘルパー関数内から早期に戻る方法は?

だから、もともとそれが

func_A(stuff): 
    if stuff == guard_condition: 
     return early 
    things = boilerplate + stuff 
    do A-specific stuff(things) 
    return late 

func_b(stuff): 
    if stuff == guard_condition: 
     return early 
    things = boilerplate + stuff 
    do B-specific stuff(things) 
    return late 

だったと私は

_helper(stuff): 
    if stuff == guard_condition: 
     return early 
    things = boilerplate + stuff 
    return things 

func_A(stuff): 
    things = _helper(stuff) 
    do A-specific stuff(things) 
    return late 

func_B(stuff): 
    things = _helper(stuff) 
    do B-specific stuff(things) 
    return late 

にそれを変更しかし、私はそれを試してみましたが、私は早く戻って(「警備員」を移動していたので、ことに気づきました?)をヘルパー機能に組み込むと、彼らはもはや機能しなくなりました。これらのケースを処理する元の関数に簡単にコードを追加することができましたが、複雑さを個々の関数に再帰させて繰り返すことなく、これを行う方法はないようです。

このような状況を処理する最もエレガントな方法は何ですか?

+0

オハイオ州、これはデコレータのためのものですか? – endolith

+0

[ガードを実装するためにPythonデコレータを使用する](http://www.siddharta.me/2006/12/using-python-decorators-to-implement.html) – endolith

+0

ああ、しかし、ラップされる関数が異なる数の引数を取る場合デコレータで '* args'を使う必要があります。これが関数シグネチャになります。これは醜いものです。 – endolith

答えて

2

ヘルパー関数に渡されるコア関数に対してa-specific stuffおよびb-specific stuffを抽出することができます。

_helper(stuff): 
    if guard: 
     return False 
    boilerplate 
    return True 

func_a(stuff): 
    if _helper(): 
     do a-specific stuff 
    return 

func_b(stuff): 
    if _helper(): 
     do b-specific stuff 
    return 
+0

ええと、それは戻り値を持っています。私は私の例を実際のコードのようにするべきだと思う。 – endolith

+0

同じ原則を使うこともできる。戻り値を、追加された要素が '_helper'が早期リターンパスまたはフルパスを通過したかどうかを示すタプルにします。 – mtrw

+0

はい、それは私が "元の関数に複雑さを戻す"という意味です – endolith

2

:私は_helper戻り値を与えるだろうHELPER

から復帰VALSの理解前

_helper(stuff, _core_func): 
    if stuff == guard_condition: 
     return early 
    things = boilerplate 
    return _core_func(things) 

_a_core(_things): 
    do a-specific stuff 
    return late 

_b_core(_things): 
    do b-specific stuff 
    return late 

func_A(stuff): 
    return _helper(stuff, _a_core) 

func_B(stuff): 
    return _helper(stuff, _b_core) 

EARLIER ANSWER、:そして、ヘルパーはコア機能を呼び出すかどうかを決定しますこれは役に立ちますか?

def common_stuff(f): 
    def checked_for_guards(*args, **kwargs): 
     if stuff == guard_condition: 
      return early 
     things = boilerplate 
     else: 
      return f(*args, **kwargs) 
    return checked_for_guards 

@common_stuff 
def func_A(stuff): 
    do A-specific stuff(things) 
    return late 

@common_stuff 
def func_b(stuff): 
    do B-specific stuff(things) 
    return late 
+0

私が考えなかったことは、func_Aとfunc_Bは引数の数が異なりますが、それはラッパー関数が '* args'を使う必要があることを意味し、それはラップされる関数のシグネチャになるでしょう醜いので、私は他のソリューションを使用する必要があると思う。 – endolith

+0

上記のコードは、func_aとfunc_bの両方の型または引数に対して機能します。ラップされた関数は、受け取ったすべての引数をそのままfunc_aまたはfunc_bに渡します。 – DurgaDatta

関連する問題