dict.setdefault() 当值已经存在时使用

dict.setdefault() is used when value already exists

我正在尝试向现有字典添加新键,将前一个键的值设置为默认值。

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 是如何工作的,也许这个问题有替代解决方案。

您误解了错误。 KeyError 表示您尝试在字典中查找键,但该键不存在。在这种情况下,它看起来像 profile[start+datetime.timedelta(day-1)] 给你 KeyError 并且与 setdefault 方法调用无关。

考虑如何在没有 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} 的等价物。