【问题标题】:dict.setdefault() is used when value already exists当值已经存在时使用 dict.setdefault()
【发布时间】:2019-02-15 17:42:03
【问题描述】:

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

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

【问题讨论】:

  • setdefault 的第二个参数在 setdefault 实际运行之前进行评估。
  • 函数的所有参数在函数被调用之前都会被完全评估——无论该函数是否真的要使用特定的参数。因此,在这种情况下,您将无条件地创建支出/充值/预算字典,即使在第一天,由于缺少前一天,预算计算也会失败。
  • 感谢您的解释!

标签: python dictionary setdefault


【解决方案1】:

您误解了错误。 KeyError 表示您尝试在字典中查找一个键,但该键不存在。在这种情况下,profile[start+datetime.timedelta(day-1)] 似乎给了您KeyError,并且与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} 的等效项。

    【讨论】:

    • 非常感谢!现在我必须在脑海中处理它:)
    猜你喜欢
    • 1970-01-01
    • 2014-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多