У меня есть набор функций, которые могут работать над структурой данных, где заданная функция выбирается с заданной вероятностью. Я делаю это, назначая положительное целое число для каждого в списке, 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.
Вы на самом деле попытались запустить любое из этого? '** arguments' не позволяет передавать любое количество аргументов функции.Он позволяет передавать только аргументы ключевого слова. Вы хотите '* arguments' (одна звезда). '* arguments' (или, чаще,' * args') на самом деле довольно изящный. – jbasko
Я только что опубликовал [gist] (https://gist.github.com/NoahTheDuke/6e8c88275c5e743fba971549d8b70759), показывающий, как это работает. Двойная звезда ('** args') принимает словарь и пытается помещать записи в аргументы функции, бросая остальные в' ** kwargs', если они не подходят. –