gpt4 book ai didi

python - 如何实现惰性 setdefault?

转载 作者:IT老高 更新时间:2023-10-28 20:21:46 27 4
gpt4 key购买 nike

dict.setdefault 的一个小烦恼是它总是评估它的第二个参数(当然,当给定时),即使第一个参数已经是字典中的键。

例如:

import random
def noisy_default():
ret = random.randint(0, 10000000)
print 'noisy_default: returning %d' % ret
return ret

d = dict()
print d.setdefault(1, noisy_default())
print d.setdefault(1, noisy_default())

这会产生如下输出:

noisy_default: returning 4063267
4063267
noisy_default: returning 628989
4063267

正如最后一行所确认的,noisy_default 的第二次执行是不必要的,因为此时 key 1已存在于 d 中(值为 4063267 )。

是否可以实现 dict 的子类?谁的setdefault方法懒惰地评估它的第二个参数?


编辑:

以下是受 BrenBarn 的评论和 Pavel Anossov 的回答启发的实现。在此过程中,我继续实现了 get 的惰性版本,因为基本思想基本相同。

class LazyDict(dict):
def get(self, key, thunk=None):
return (self[key] if key in self else
thunk() if callable(thunk) else
thunk)


def setdefault(self, key, thunk=None):
return (self[key] if key in self else
dict.setdefault(self, key,
thunk() if callable(thunk) else
thunk))

现在,片段

d = LazyDict()
print d.setdefault(1, noisy_default)
print d.setdefault(1, noisy_default)

产生这样的输出:

noisy_default: returning 5025427
5025427
5025427

注意 d.setdefault 的第二个参数上面现在是可调用的,而不是函数调用。

当第二个参数为LazyDict.getLazyDict.setdefault不是可调用的,它们的行为方式与相应的 dict 相同方法。

如果想要传递一个可调用对象作为默认值本身(即,意味着要调用),或者如果要调用的可调用对象需要参数,请在前面加上 lambda:到适当的论点。例如:

d1.setdefault('div', lambda: div_callback)

d2.setdefault('foo', lambda: bar('frobozz'))

那些不喜欢重写 get 的人和 setdefault ,和/或因此需要测试可调用性等,可以改用此版本:

class LazyButHonestDict(dict):
def lazyget(self, key, thunk=lambda: None):
return self[key] if key in self else thunk()


def lazysetdefault(self, key, thunk=lambda: None):
return (self[key] if key in self else
self.setdefault(key, thunk()))

最佳答案

这也可以通过 defaultdict 来完成。它使用可调用对象实例化,然后在访问不存在的元素时调用该对象。

from collections import defaultdict

d = defaultdict(noisy_default)
d[1] # noise
d[1] # no noise

defaultdict 的警告是可调用对象没有参数,因此您不能像使用 dict.setdefault 那样从键中派生默认值。这可以通过在子类中覆盖 __missing__ 来缓解:

from collections import defaultdict

class defaultdict2(defaultdict):
def __missing__(self, key):
value = self.default_factory(key)
self[key] = value
return value

def noisy_default_with_key(key):
print key
return key + 1

d = defaultdict2(noisy_default_with_key)
d[1] # prints 1, sets 2, returns 2
d[1] # does not print anything, does not set anything, returns 2

有关详细信息,请参阅 collections模块。

关于python - 如何实现惰性 setdefault?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17532929/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com