2017-02-01 12 views
0

現在、私のプログラムには15個以上のパラメータを含むいくつかの関数があります。しかし、15のパラメータはすべて同時に必要とされることはありません。関数のパラメータの数を減らす

辞書を使用して、必要な関連する機能を実行するswitch文機能がいくつかあります。私の最も極端な例を以下に見ることができます。

def Instrument_Type_Calcs_C(InstType_C, raw_data_LP, maxcounts_C, Measurement_Min, 
          Measurement_Max, Measurement_Type, SG, Tank_Shape, area, dish, 
          diameter, length, Strapping_Table, Poly_Data, Tank_Number, 
          LevelOffset): 
    switcher = { 
     '8AI': lambda: inst.FourTwenty(raw_data_LP, maxcounts_C, Measurement_Min, 
             Measurement_Max, Measurement_Type, SG, Tank_Shape, 
             area, dish, diameter, length, Strapping_Table, 
             Poly_Data, Tank_Number, LevelOffset), 
     'Magprobe': lambda: inst.SGMagprobe(raw_data_LP, 
              Tank_Shape, area, dish, diameter, length, 
              Strapping_Table, Poly_Data, Tank_Number, 
              LevelOffset), 
     'TLS': lambda: inst.TLS(raw_data_LP), 
    } 
    return switcher.get(InstType_C, lambda : None)() 

は、今私は*args**kwargsに探して試してみましたが、これらは私を助ける場合、私はわかりませんよ。関数を定義するために*argsを使用する場合、関数を呼び出すときにすべての引数を定義する必要があります。しかし、適切な量の引数を宣言するには、if: elif:ステートメントに3つの異なる関数呼び出しが必要です。明らかに、これはスイッチステートメントのポイントを打ち消し、本当に長い関数呼び出しの問題を解決しません。

全体的には自分のコードに問題はありませんが、実装する方が良い場合は、どのようにしたらいいか教えてください。

+3

デフォルトパラメータを使用してみましたか? 'Def Instrument_Type_Calcs_C(InstType_C、raw_data_LP = None、...)' –

答えて

0

デフォルトのパラメータと名前付きパラメータを使用して問題を解決できます。

しかし、それほど多くのパラメータを持つ関数が必要な場合は、おそらくプログラムをオブジェクト指向にすることができます。

クラスを作成します。クラスのインスタンスは、ほとんどの場合使用するパラメータを特色にした__call__演算子(または単なるメソッド)を持ちます。

さらに、変更の頻度の低い設定を制御する他の方法を指定します。

-1

引数のような辞書 "パラメータ"を使用すると、必要なすべてのパラメータを入れることができます。このような何か:

def FoobarFunction(parameters): 
    if parameters["KnownParameter"] == ... : 
     # Do Something 
     ... 
+0

これはパラメータとして '** kwargs'を定義することで実現できます。 – nlsdfnbch

+0

はい、別の方法です。 Buは辞書がより明確です。 – Denr2

+0

私は強く同意します。それだけではない、あなたはまた、辞書を最初に初期化する必要があります。 kwargsを使用するとこれが回避されます。 – nlsdfnbch

0

使用のデフォルトのいずれかのパラメータ(すなわち、コメントでdef func(a, optional=None, optional2=None ...):を指摘されているか、また、これを行うことができますよう:

def Instrument_Type_Calcs_C(InstType_C, **kwargs): 
    # You can also simply added a proper list of strings, I was merely to lazy to write on up 
    allowed_kwargs = ('raw_data_LP, maxcounts_C, Measurement_Min, 
           Measurement_Max, Measurement_Type, SG, Tank_Shape, area, 
           dish, diameter, length, Strapping_Table, Poly_Data, 
           Tank_Number, LevelOffset').strip(' ').split(',') 
    wrong_kwargs = [k for in kwargs if k not in allowed_kwargs] 
    if wrong_kwargs: 
     raise ValueError("Invalid Kwarg passed! %s" wrong_kwargs) 

    # rest of your code 
    ... 

kwargsはに詰め込ますべての名前付きパラメータのadictです辞書にアクセスするのと同じように、あなたの関数内でアクセスすることができます。

しかし、指摘されているように、あなたのコードをoopと考えるべきでしょう。関数の読みやすさではなく、関数ヘッダーをクリーンアップしたり、シンプルさを改善することはできません。

ところで、あなたもあなたの関数内でスターを付けた表現(***)を使用することができます - 彼らは基本的にリスト(*)または辞書(**)を解凍します。これは、例えば、リストの内包表記に有用ですまたは他の変数を開梱するとき:

l = ['hello', 1, 2] 
s, *nums = *l 

s # 'hello' 

nums # [1, 2] 
1

あなたは、スイッチング機能は、すべてのそれの最初の引数、InstType_C、キーワード引数を受け取る作ることができます。これにより、各呼び出しで渡す値を指定することができます。

これを説明するために、私はあなたのサンプルコードに適用しました。実際に実行可能なものを作るために、コードから除外されているものがいくつか追加されていますが、これはテスト目的のためだけです。

これは、それほど改善されていないように見えるかもしれませんが、テストのために、独自の名前を含む変数が定義されているためです。これは、各キーワード引数に同じ名前の変数の値が割り当てられているため、スイッチャー関数の呼び出しを長くしているため、実際の長さの2倍の長さになります。

すべてのテストコードでは、これは非常に長くて複雑に見えますが、目的の目的の利点を十分に理解していただければ幸いです。

PEP 8 - Style Guide for Python Code命名規則に従わないという事実も、構文強調表示SOが表示されたコードに適用されるので、「ビジー」に見えます。

# For testing define and create a class with methods to call. 
# Each method will just print out the values of the arguments it was passed. 
class Inst(object): 
    def FourTwenty(self, *args): 
     print('called FourTwenty({})\n'.format(args)) 
    def SGMagprobe(self, *args): 
     print('called SGMagprobe({})\n'.format(args)) 
    def TLS(self, *args): 
     print('called TLS({})\n'.format(args)) 

inst = Inst() # create instance for testing 

# For testing create variables to pass as arguments, each variable will contain 
# the variable's name as its value. i.e. some_variable = 'some_variable'. 
arguments = [arg.strip() for arg in (
    "raw_data_LP, maxcounts_C, Measurement_Min, Measurement_Max, " 
    "Measurement_Type, SG, Tank_Shape, area, dish, diameter, length, " 
    "Strapping_Table, Poly_Data, Tank_Number, LevelOffset").split(',')] 
for arg in arguments: 
    globals()[arg] = arg 

#### End of testing scaffold. 

class AttrDict(dict): 
    """Allows use of dot notation to access dictionary's contents.""" 
    def __init__(self, *args, **kwargs): 
     super(AttrDict, self).__init__(*args, **kwargs) 
     self.__dict__ = self 

def Instrument_Type_Calcs_C(InstType_C, **kwargs): 
    kwargs = AttrDict(kwargs) # make them easier to access 

    switcher = { 
     '8AI': lambda: inst.FourTwenty(kwargs.raw_data_LP, kwargs.maxcounts_C, 
             kwargs.Measurement_Min, 
             kwargs.Measurement_Max, kwargs.Measurement_Type, 
             kwargs.SG, kwargs.Tank_Shape, kwargs.area, kwargs.dish, 
             kwargs.diameter, kwargs.length, kwargs.Strapping_Table, 
             kwargs.Poly_Data, kwargs.Tank_Number, kwargs.LevelOffset), 
     'Magprobe': lambda: inst.SGMagprobe(kwargs.raw_data_LP, kwargs.Tank_Shape, kwargs.area, 
              kwargs.dish, kwargs.diameter, kwargs.length, 
              kwargs.Strapping_Table, kwargs.Poly_Data, 
              kwargs.Tank_Number, kwargs.LevelOffset), 
     'TLS': lambda: inst.TLS(kwargs.raw_data_LP), 
    } 
    return switcher.get(InstType_C, lambda: None)() 

volume = Instrument_Type_Calcs_C('8AI', raw_data_LP=raw_data_LP, 
           maxcounts_C=maxcounts_C, Measurement_Min=Measurement_Min, 
           Measurement_Max=Measurement_Max, 
           Measurement_Type=Measurement_Type, SG=SG, 
           Tank_Shape=Tank_Shape, area=area, dish=dish, 
           diameter=diameter, length=length, 
           Strapping_Table=Strapping_Table, Poly_Data=Poly_Data, 
           Tank_Number=Tank_Number, LevelOffset=LevelOffset) 
volume = Instrument_Type_Calcs_C('Magprobe', raw_data_LP=raw_data_LP, SG=SG, 
           Tank_Shape=Tank_Shape, area=area, dish=dish, 
           diameter=diameter, length=length, 
           Strapping_Table=Strapping_Table, Poly_Data=Poly_Data, 
           Tank_Number=Tank_Number, LevelOffset=LevelOffset) 
volume = Instrument_Type_Calcs_C('TLS', raw_data_LP=raw_data_LP) 
関連する問題