dict.setdefault() используется, когда значение уже существует

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

def check_data(end, start, profile):
    print(profile)

    for day in range((end-start).days+1):
        profile.setdefault(start+datetime.timedelta(day),
           {'expediture':0, 'top-up':0,
           'budget':profile[start+datetime.timedelta(day-1)]['budget'] })

start  = datetime.date(2019,2,1)
end    = datetime.date(2019,2,17)
check_data(end, start, month_data)

вывод из print(profile):

    {datetime.date(2019, 2, 1): {'expediture': 0, 'top-up': 0, 'budget': 100.0}}

 ---------------------------------------------------------------------------
    KeyError                                  Traceback (most recent call last)
    <ipython-input-4-e44462627692> in <module>
    ----> 1 check_data(end, start, month_data)

    <ipython-input-2-90b936150b04> in check_data(end, start, profile)
         20         profile.setdefault(start+datetime.timedelta(day),
         21                                     {'expediture':0, 'top-up':0,
    ---> 22
       'budget':profile[start+datetime.timedelta(day-1)]['budget'] })
        23
        24 def add_money(profile, topup, date=datetime.date.today()):

       KeyError: datetime.date(2019, 1, 31)

Я не понимаю почему setdefault() пытается установить значение по умолчаниюdatetime.date(2019, 2, 1) если это значение уже существует.

Я мог бы решить эту проблему с if но я хотел бы понять, как setdefault работает и, возможно, есть альтернативное решение этой проблемы.

2 ответа

Решение

Подумайте, как бы вы написали этот код без setdefault (и незначительный рефакторинг для удобства чтения):

def check_data(end, start, profile):
    print(profile)

    for day in range((end-start).days+1):
        yesterday = start + datetime.timedelta(day - 1)
        today = start + datetime.timedelta(day)
        profile[today] = {
            'expenditure': 0,
            'top-up': 0,
            'budget': profile[yesterday]['budget']
        }

start  = datetime.date(2019,2,1)
end    = datetime.date(2019,2,17)
check_data(end, start, month_data)

На первой итерации цикла вам нужно значение profile[datetime(2019,1,31)] для того, чтобы установить значение profile[datetime(2019,2,1)], но это значение никогда не было установлено.

Единственное использование для setdefault здесь будет с ключом yesterdayпри условии, что вы можете начать с какого-то общего профиля. Для простоты предположу, что budget также целое число.

def check_data(end, start, profile):
    print(profile)

    for day in range((end-start).days+1):
        yesterday = start + datetime.timedelta(day - 1)
        today = start + datetime.timedelta(day)
        profile[today] = {
            'expenditure': 0,
            'top-up': 0,
            'budget': profile.setdefault(yesterday, {'budget': 0})['budget']
        }

Сейчас если profile[yesterday] не существует, setdefault выполнит эквивалент profile[yesterday] = {'budget': 0} перед возвратом этого значения.

Вы неправильно истолковали ошибку. KeyError означает, что вы пытались найти ключ в словаре, но этот ключ не существует. В этом случае это выглядит как profile[start+datetime.timedelta(day-1)] дает вам KeyError и не имеет отношения к setdefault вызов метода.

Другие вопросы по тегам