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.
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.