【问题标题】:Best practice for conditionally getting values from Python dictionary [closed]从 Python 字典有条件地获取值的最佳实践 [关闭]
【发布时间】:2020-01-27 06:09:07
【问题描述】:

我有一本结构相当标准的 Python 字典。如果存在,我想检索一个值,如果不检索另一个值。如果由于某种原因两个值都丢失了,我需要抛出一个错误。

字典示例:

# Data that has been modified
data_a = {
    "date_created": "2020-01-23T16:12:35+02:00",
    "date_modified": "2020-01-27T07:15:00+02:00"
}

# Data that has NOT been modified
data_b = {
    "date_created": "2020-01-23T16:12:35+02:00",
}

对此的最佳做法是什么?什么是一种直观且易于阅读的方法?

我目前这样做的方式:

mod_date_a = data_a.get('date_modified', data_a.get('date_created', False))
# mod_data_a = "2020-01-27T07:15:00+02:00"

mod_date_b = data_b.get('date_modified', data_b.get('date_created', False))
# mod_data_b = "2020-01-23T16:12:35+02:00"

if not mod_date_a or not mod_date_b:
    log.error('Some ERROR')

这个嵌套的get() 看起来有点笨拙,所以我想知道是否有人对此有更好的解决方案。

【问题讨论】:

    标签: python python-3.x dictionary


    【解决方案1】:

    如果你经常需要这个,为它写一个函数是完全合理的:

    def get_or_error(d, *keys):
        for k in keys:
            try:
                return d[k]
            except KeyError:
                pass
        else:
            raise KeyError(', '.join(keys))
    
    print(get_or_error(data_a, 'date_modified', 'date_created'))
    

    【讨论】:

    • 这看起来也不错。就我而言,我更喜欢单线,因为它只需要一次。
    • ……至少现在是这样。一旦您发现自己再次键入相同的单行代码,请考虑使用一个函数。它真的取决于你想要的“错误”。没有合理的单行代码也可以记录或引发异常……
    • 为什么不直接使用in 而不是try-except?
    • @Rusi 取决于您的错误处理理念。 EAFP 通常被认为更 Pythonic,但您当然可能不同意。
    【解决方案2】:
    value = data_a['date_modified' if 'date_modified' in data_a else 'date_created']
    

    【讨论】:

    • 这完全符合您的要求(如果第一个丢失,请尝试第二个,如果两个都丢失,则引发错误)并且如果您的字典中有一个虚假值,也可以正常工作。
    • 我觉得它读起来有点重复和笨拙,但它肯定是一个单行字,也会引发KeyError。虽然 KeyError 可能会有点误导,因为它只会提到第二个键,但这是一个小问题。
    【解决方案3】:

    假设没有错误值并且您并不真正需要False,而只是任何错误:

    mod_date_a = data_a.get('date_modified') or data_a.get('date_created')
    

    【讨论】:

    • 这实际上更具可读性,谢谢!不,我并不特别需要 False,我只是让它更清楚什么时候应该失败。如果没有 False,它同样适用于我的鳕鱼。
    • @HeapOverflow 如果您想要检索虚假的date_modified,则可以将第二个get 作为默认值传递:data_a.get('date_modified', data_a.get('date_created')) 将仅在修改日期时返回创建日期完全丢失,但如果它存在并且例如None。如果需要后备,您可能还需要使用常规索引 ([])。
    • @Masklinn “如果需要回退 [..]” — 你的意思是 d.get('m', d['c'])?如果c 不存在,即使m 确实存在,那也会出错……
    • 您可能应该添加一条评论,说明您假设 dict 永远不会在您使用此 sn-p 时包含虚假值。我认为@deceze 的回答更好。
    • @Boris 为什么我已经在答案中说过,我还要在评论中这么说?
    【解决方案4】:

    你可以使用next()

    def get_first(d, *keys):
        return next(d[key] for key in keys if key in d)
    

    如果没有找到密钥,这将引发StopIteration。此外,大声朗读时听起来很有趣,这通常意味着它是 pythonic ;)

    【讨论】:

    • 最佳答案 Afaic。您可以尝试将虚假的 StopIteration 转换为正确的 KeyError ...重新提高 @couple 额外行?
    • @Rusi KeyError 会说字典中没有任何键,而 StopIteration 说所有键都被循环遍历而没有找到任何东西¯_(ツ)_/¯
    猜你喜欢
    • 1970-01-01
    • 2010-09-27
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 2010-10-06
    • 2011-10-28
    • 2010-09-10
    相关资源
    最近更新 更多