Я хочу написать программу, которая показывает все возможные способы, которыми комбинация разных монет (5c, 10c, 50c и т. Д.) Может составлять определенное значение (например, 4 доллара). Скажем, для начала я хочу рассмотреть только 50c, $ 1 и 2 $ в возможных комбинациях. Если я хочу использовать грубую силу, я мог бы написать 3 вложенных цикла while
и возвращать эту комбинацию валют каждый раз, когда они суммируют до желаемого значения (в данном случае, 4 доллара). Однако, поскольку мы рассматриваем больше вариантов валюты (например, 1c, 5c, 10c, 25c, 50c, $ 1, $ 2, $ 5, $ 10, $ 50, $ 100) и большие суммы (скажем, я хочу, чтобы все комбинации получали 400 $), код становится очень многословным и трудным в обслуживании. Если я хочу создать общий алгоритм, который работает для любой страны и комбинации валют, я не могу полагаться на простое вложение циклов.
Учитывая эту проблему, я попытался использовать декораторы, чтобы я мог вкладывать циклы в одну функцию:
INTENDED_SUM = 400
coin_count = {
200: 0,
100: 0,
50: 0,
}
def max_range(value):
return INTENDED_SUM / value
def coin_loop(coin_value):
def decorator(func):
while coin_count[coin_value] <= max_range(coin_value):
yield from func()
coin_count[coin_value] += 1
else:
coin_count[coin_value] = 0
return decorator
@coin_loop(100)
def get_combinations():
agg = sum([i * coin_count[i] for i in coin_count])
if agg == INTENDED_SUM:
yield coin_count
for i in get_combinations:
print(i)
Это вывод:
{200: 0, 100: 4, 50: 0}
Однако, если я добавляю несколько декораторов к функции get_combinations()
, возникает ошибка TypeError:
@coin_loop(200)
@coin_loop(100)
@coin_loop(50)
def get_combinations():
agg = sum([i * coin_count[i] for i in coin_count])
if agg == INTENDED_SUM:
yield coin_count
Traceback (most recent call last):
File "31-coin_sums.py", line 29, in <module>
for i in get_combinations:
File "31-coin_sums.py", line 15, in decorator
yield from func()
TypeError: 'generator' object is not callable
Итак, у меня два вопроса:
Почему get_combination уже отображается как генератор, и его не нужно вызывать, когда я вызываю его в последних 2 строках кода? Разве они не должны быть такими?
for i in get_combinations():
print(i)
Почему в этом случае не работает вложенность декоратора? Ожидаемый результат должен быть примерно таким:
{200: 2, 100: 0, 50: 0}
{200: 1, 100: 2, 50: 0}
{200: 1, 100: 1, 50: 2}
{200: 1, 100: 0, 50: 4}
{200: 0, 100: 4, 50: 0}
{200: 0, 100: 3, 50: 2}
{200: 0, 100: 2, 50: 4}
{200: 0, 100: 1, 50: 6}
{200: 0, 100: 0, 50: 8}
РЕДАКТИРОВАТЬ: просто в качестве примера, я хочу, чтобы приведенный выше код (с несколькими декораторами) был эквивалентен этому, кроме как без вложенного whiles
:
INTENDED_SUM = 400
coin_count = {
200: 0,
100: 0,
50: 0,
}
def max_range(value):
return INTENDED_SUM / value
def get_combinations():
while coin_count[200] <= max_range(200):
while coin_count[100] <= max_range(100):
while coin_count[50] <= max_range(50):
agg = sum([i * coin_count[i] for i in coin_count])
if agg == INTENDED_SUM:
yield coin_count
coin_count[50] += 1
else:
coin_count[50] = 0
coin_count[100] += 1
else:
coin_count[100] = 0
coin_count[200] += 1
else:
coin_count[200] = 0
for i in get_combinations():
print(i)