У меня есть две очень похожие петли, и эти два содержат внутренний цикл, который очень похож на третий цикл (eh ... :)). Иллюстрированный с кодом выглядит близко к этому:Дедублирующий код в несколько разных функциях
# First function
def fmeasure_kfold1(array, nfolds):
ret = []
# Kfold1 and kfold2 both have this outer loop
for train_index, test_index in KFold(len(array), nfolds):
correlation = analyze(array[train_index])
for build in array[test_index]: # <- All functions have this loop
# Retrieved tests is calculated inside the build loop in kfold1
retrieved_tests = get_tests(set(build['modules']), correlation)
relevant_tests = set(build['tests'])
fval = calc_f(relevant_tests, retrieved_tests)
if fval is not None:
ret.append(fval)
return ret
# Second function
def fmeasure_kfold2(array, nfolds):
ret = []
# Kfold1 and kfold2 both have this outer loop
for train_index, test_index in KFold(len(array), nfolds):
correlation = analyze(array[train_index])
# Retrieved tests is calculated outside the build loop in kfold2
retrieved_tests = _sum_tests(correlation)
for build in array[test_index]: # <- All functions have this loop
relevant_tests = set(build['tests'])
fval = calc_f(relevant_tests, retrieved_tests)
if fval is not None:
ret.append(fval)
return ret
# Third function
def fmeasure_all(array):
ret = []
for build in array: # <- All functions have this loop
relevant = set(build['tests'])
fval = calc_f2(relevant) # <- Instead of calc_f, I call calc_f2
if fval is not None:
ret.append(fval)
return ret
Первые две функции отличаются только в порядке, и в какое время, они вычисляют retrieved_tests
. Третья функция отличается от внутренней петли первых двух функций тем, что она вызывает calc_f2
и не использует retrieved_tests
.
В действительности код более сложный, но пока дублирование меня раздражало, я решил, что смогу жить с ним. Тем не менее, в последнее время я вносил в него изменения, и это раздражает, чтобы изменить его в двух или трех местах одновременно.
Есть ли хороший способ объединить дублированный код? Единственный способ, с помощью которого я мог думать, заключался в том, чтобы вводить классы, которые вводят множество шаблонов, и я хотел бы сохранить функции как чистые функции, если это возможно.
Редактировать
Это содержимое calc_f
и calc_f2
:
def calc_f(relevant, retrieved):
"""Calculate the F-measure given relevant and retrieved tests."""
recall = len(relevant & retrieved)/len(relevant)
prec = len(relevant & retrieved)/len(retrieved)
fmeasure = f_measure(recall, prec)
return (fmeasure, recall, prec)
def calc_f2(relevant, nbr_tests=1000):
"""Calculate the F-measure given relevant tests."""
recall = 1
prec = len(relevant)/nbr_tests
fmeasure = f_measure(recall, prec)
return (fmeasure, recall, prec)
f_measure
вычисляет harmonic mean точности и отзывом.
В принципе, calc_f2
берет много ярлыков, поскольку требуемые тесты не требуются.
Как 'calc_f' и' calc_f2' отличаются? –
Я отредактировал вопрос, чтобы добавить информацию об этих функциях. – imolit
Изначально это 'calc_f2' принимает два аргумента (и использует второй аргумент), но' fmeasure_all' вызывает его только одним аргументом. Я полагаю, что это следствие «упрощения» кода. –