简体   繁体   中英

dict.setdefault() is used when value already exists

I'm trying to add new keys to the existing dictionary, setting as default value, the value of the previous key.

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)

output from 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)

I don't understand why setdefault() tries to set default value to datetime.date(2019, 2, 1) if this value already exists.

I could fix this problem with if but I'd like to understand how setdefault works and maybe there is alternative solution for this problem.

You are misinterpreting the error. A KeyError means you tried to look up a key in a dictionary but that key does not exist. In this case it looks like profile[start+datetime.timedelta(day-1)] is giving you the KeyError and is not related to the setdefault method call.

Consider how you would write this code without setdefault (and some minor refactoring for readability):

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)

On the first iteration of the loop, you need the value of profile[datetime(2019,1,31)] in order to set the value of profile[datetime(2019,2,1)] , but that value was never set.

The only use for setdefault here would be with the key yesterday , assuming you could start with some generic profile. For simplicity, I'll assume that budget is also an integer.

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']
        }

Now, if profile[yesterday] doesn't already exist, setdefault will execute the equivalent of profile[yesterday] = {'budget': 0} before returning that value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM