2017-01-03 10 views
1

私は、所定の関数が所定の確率で選択されるデータ構造上で動作する関数の集合を持っています。リストに-ing私は、リスト中の各正の整数を割り当てることによって、これを行うitertools.accumulateは重みを-ing、その後、bisect多くの関数の1つに可変数の引数を適用する

func_weights = list(accumulate(weights)) 
probability = bisect(func_weights, random.random() * func_weights[-1]) 

問題は、これらの機能のそれぞれがわずかに異なるセットを持っていることを来りますパラメータ/引数。それらの中にはデータ構造だけを必要とするものもあれば、プログラムの残りの部分から追加情報を必要とするものもあります。今、私は辞書へのすべての呼び出しのための追加情報を構築し、私のような各機能を見て持つことができるように、func[probability](data_struct, **arguments)として関数に渡します。これは十分に機能

funcs = [func_1, func_2, func_3, ...] 
weights = [1, 2, 3, ...] 

func_weights = list(accumulate(weights)) 
probability = bisect(func_weights, random.random() * func_weights[-1]) 
funcs[probability](data_struct, **arguments) 

# ... 

def func_1(data_s, arg_1, **kwargs): 
    # blah blah blah 

def func_2(data_s, arg_2, **kwargs): 
    # blah blah blah 

def func_3(data_s, arg_1, arg_2, **kwargs): 
    # blah blah blah 

を、と私はかなりスマートに感じました私は最終的にそれがすべて設定しまったが、私はdata_structureを少し変更し、そして今、このからくりの両方の部分を再考えていたとき:

  • まず、引数のいくつかは、ランダムな数字なので、代わりにすべての関数でrandom.random()を呼び出すと、私はbuild_arguments()で1回呼びます。私はこれを考えたことがありますか?

  • 第2に、**argumentsではなく、手の込んだスイッチスタイルのステートメントを設定するほうが賢明でしょうか?インデックスに二分し、funcの名前をつかみ、if-then正しい関数を取得します。

例:第三に、点の横に少し

if name == 'func_1': 
    func_1(data_struct, arg_1) 
elif name == 'func_2': 
    func_2(data_struct, arg_2) 
elif name == 'func_3': 
    func_3(data_struct, arg_1, arg_2) 
# etc etc 
  • 、これらの機能の全ては、代わりに純粋であることの、構造内のデータを直接操作します。 data_structure全体ではなく、変更される要素だけを渡すほうが賢明でしょうか?

例:

data_s[:] = func_3(data_struct.alist, arg_1, arg_2) 

# ... 

def func_3(alist, arg_1, arg_2, **kwargs): 
    temp = alist[:arg_1] + alist[arg_2:] 
    point = random.randint(len(temp)) 
    return temp[:point] + alist[arg_1:arg_2] + temp[point:] 

func_3(data_struct, arg_1, arg_2) 

# ... 

def func_3(data_s, arg_1, arg_2, **kwargs): 
    alist = data_s.alist 
    temp = alist[:arg_1] + alist[arg_2:] 
    point = random.randint(len(temp)) 
    data_s.alist[:] = temp[:point] + alist[arg_1:arg_2] + temp[point:] 

本当にありがとうございました!


編集:混乱があるようです。私は小さなエラーを修正しましたが、そうでない場合は、in this gist I just createdのように、3.4と3.5の両方で説明したように動作します。

+1

実際に試してみましたか? '** arguments'では、関数に引数をいくつでも渡すことはできません。キーワード引数のみを渡すことができます。 '* arguments'(1つ星)が必要です。 '* arguments'(あるいはもっと一般的には' * args')は実際にはかなりエレガントです。 – jbasko

+0

これはどのように動作するかを示す[gist](https://gist.github.com/NoahTheDuke/6e8c88275c5e743fba971549d8b70759)を投稿しました。二重星( '** args')は辞書をとり、関数の引数にその項目を当てはめ、残りが' 'kwargs''に収まるようにしようとします。 –

答えて

0

あなたの質問に対する私の解釈が正しい場合は、これを基にしたいと思うかもしれません。

私の解釈は、適切な数の引数をランダムに選択し、引数をランダムに生成して、多くの関数の1つを実行したいということです。

あなたの確率モデルに合わせて関数の選択を変更する必要があります。

import inspect 
import random 

def func1(): 
    pass 

def func2(): 
    pass 

def func3(): 
    pass 

functions = [ 
    func1, func2, func3 
] 

random_func = random.choice(functions) 
random_args = [random.randint(1, 10) for i in range(len(inspect.getfullargspec(random_func).args))] 
random_func(*random_args) 
関連する問題