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

时间:2019-02-15 17:42:03

标签: python dictionary 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 个答案:

答案 0 :(得分:1)

您误解了该错误。 KeyError表示您试图在字典中查找键,但是该键不存在。在这种情况下,profile[start+datetime.timedelta(day-1)]似乎为您提供了KeyError,并且与setdefault方法调用无关。

答案 1 :(得分:0)

考虑如何在没有 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}等效的操作,然后返回该值。