2017-01-03 2 views
1

У меня есть набор функций, которые могут работать над структурой данных, где заданная функция выбирается с заданной вероятностью. Я делаю это, назначая положительное целое число для каждого в списке, itertools.accumulate -ную веса, а затем bisect -ную в списке:Применение переменного количества аргументов к одной из многих функций

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(). Разве я думал об этом?

  • И во-вторых, было бы разумнее настроить сложную инструкцию в стиле switch вместо **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?

Пример:

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:] 

против

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:] 

Спасибо так много!


Редактировать: Похоже, есть некоторые путаницы. Я исправил небольшую ошибку, но в остальном это работает как описано как в 3.4, так и в 3.5, как показано in this gist I just created.

+1

Вы на самом деле попытались запустить любое из этого? '** arguments' не позволяет передавать любое количество аргументов функции.Он позволяет передавать только аргументы ключевого слова. Вы хотите '* arguments' (одна звезда). '* arguments' (или, чаще,' * args') на самом деле довольно изящный. – jbasko

+0

Я только что опубликовал [gist] (https://gist.github.com/NoahTheDuke/6e8c88275c5e743fba971549d8b70759), показывающий, как это работает. Двойная звезда ('** args') принимает словарь и пытается помещать записи в аргументы функции, бросая остальные в' ** kwargs', если они не подходят. –

ответ

0

Если моя интерпретация вашего вопроса верна, вы можете использовать это.

Моя интерпретация заключается в том, что вы хотите запустить одну из многих функций с правильным количеством аргументов с функцией, выбранной случайным образом, и аргументами, генерируемыми случайным образом.

Вам необходимо будет изменить выбор функции, чтобы она соответствовала вашей модели вероятности.

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) 
Смежные вопросы