Python - 函数如dict.get但返回默认键的值而不是默认值?

时间:2018-03-22 10:14:29

标签: python

让我们说

a = {1:2, 3:4, 5:6}

是否有内置函数(可能类似a.get2(7,5))会返回a[7],或a[5]如果a[7]不存在?

这样的功能可以很容易地定义为a.get(val, a.get(def_key)),但如果存在则更喜欢内置解决方案。

3 个答案:

答案 0 :(得分:2)

你可以继承dict

class MyDict(dict):
    def get2(self,*keys):
        for k in keys:
            if k in self:
                return self.get(k)
        return None  # if not found

a = {1:2, 3:4, 5:6}
b = MyDict(a)
print(b.get2(2,10,5))

位置参数允许将行为扩展到n个键。一般情况下无法使用get来了解密钥是否在dict中,因为某些值可能 None因此in测试。

避免使用 sentinel对象进行双dict测试

class MyDict(dict):
    __notfound = object()
    def get2(self,*keys):
        for k in keys:
            x = self.get(k,self.__notfound )
            if x is not self.__notfound :
               return x
        return None  # if not found

答案 1 :(得分:1)

可以设置常量回退值。一种方法是使用collections.defaultdict

请注意,这需要创建一个新词典。当然,我们可以分配给同一个变量。

from collections import defaultdict

a = {1:2, 3:4, 5:6}

a = defaultdict(lambda: a[5], a)

这会将默认值设置为常量6,这将在找不到密钥时返回。如果需要,您每次更新a[5]时都必须重置默认值。

答案 2 :(得分:1)

您可以定义dict的子类来访问具有虚拟默认值的字典条目,该默认值将应用于任何不存在的键,但在引用它们时实际上不会创建任何键(与setdefault()函数相反)< / p>

 class dictWithDefault(dict):
     def __init__(self,aDict={},defaultValue=None):
         super().__init__(aDict)
         def aFunction():pass
         self._default = defaultValue if type(defaultValue) == type(aFunction) else lambda : defaultValue
     def __getitem__(self,key):
         return super().__getitem__(key) if key in self else self._default()

 d = {1:2, 3:4, 5:6}

 d = dictWithDefault(d,99)
 d[1] # >>> 2
 d[7] # >>> 99  this is the default value, but key 7 still doesn't exist
 d[7] = 97
 d[7] # >>> 97 once assigned the key has its own value
 d._default = 100 # you can change the virtual default at any time
 d[9] # >>> 100
 d[8] += 5   # this can be useful when key/values are used to count things
             # (using a default value of zero) akin to a Bag structure
 d[8] # >>> 105
 d    # >>> {1: 2, 3: 4, 5: 6, 7: 97, 8: 105}

您也可以直接使用默认值创建字典:

d = dictWithDefault({1:2, 3:4, 5:6},99)

要使用默认密钥而不是默认值,您可以使用相同的技术,只需更改 getitem 方法的实现。

或者,您可以简单地使用d = dictWithDefault(d)而不使用默认值,并使用运算符来获取替代密钥:

d = dictWithDefault(d)
value = d[7] or d[5]

[编辑] 更改了代码以支持对象作为默认值。

使用对象(例如列表)作为字典的值时,必须小心。在对新键的第一次隐式赋值时,它只会被赋予对_default对象的引用。这意味着所有这些键最终都会引用相同的对象。

例如:d = dictWithDefault(defaultValue = [])将无法按预期工作。

d = dictWithDefault(defaultValue=[])

d["A"].append(1)
d["B"].append(2)

# will end up with { "A":[1,2], "A":[1,2] } 
# because both keys (A and B) reference the same list instance.

要解决这个问题,我更改了函数,以便接受lambda:在将对象用作默认值的情况下。

这允许默认值在用于新密钥时创建新实例。

d = dictWithDefault(defaultValue=lambda:[])

d["A"].append(1)
d["B"].append(2)

# now works properly giving: { "A":[1], "B":[2] }

对于简单类型(字符串,整数,...),您仍然可以使用没有lambda的类,但是当字典将对象存储为值时,您必须确保使用lambda:with instance creation方法。