Несколько декораторов, обертывающих функцию генератора в Python 3.7 - проблема всевозможных комбинаций монет - PullRequest
0 голосов
/ 14 ноября 2018

Я хочу написать программу, которая показывает все возможные способы, которыми комбинация разных монет (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

Итак, у меня два вопроса:

  1. Почему get_combination уже отображается как генератор, и его не нужно вызывать, когда я вызываю его в последних 2 строках кода? Разве они не должны быть такими?

    for i in get_combinations():
        print(i)
    
  2. Почему в этом случае не работает вложенность декоратора? Ожидаемый результат должен быть примерно таким:

    {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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...