可调用对象作为dict.get的默认参数,但如果键存在则不被调用
我想给字典的 get 函数提供一个默认参数,像这样:
def run():
print "RUNNING"
test = {'store':1}
test.get('store', run())
但是当我运行这个代码时,输出结果是:
RUNNING
1
所以我想问的是,标题所说的那样,有没有办法给 get 方法提供一个可以调用的默认值,而在键存在的情况下不让它被调用?
6 个回答
3
我想你是想在键不存在的时候才调用某个函数。
有几种方法可以做到这一点。第一种方法是使用一个叫做defaultdict的东西,它会在键缺失时自动调用run()
函数。
from collections import defaultdict
def run():
print "RUNNING"
test = {'store':1}
test.get('store', run())
test = defaultdict(run, store=1) # provides a value for store
test['store'] # gets 1
test['runthatstuff'] # gets None
另一种方法,虽然有点复杂,就是只在字典里保存那些能返回合适值的函数。
test = {'store': lambda:1}
test.get('store', run)() # -> 1
test.get('runrun', run)() # -> None, prints "RUNNING".
如果你想让返回值依赖于缺失的键,那你需要创建一个defaultdict的子类:
class mydefaultdict(defaultdict):
def __missing__(self, key):
val = self[key] = self.default_factory(key)
return val
d = mydefaultdict(lambda k: k*k)
d[10] # yields 100
@mydefaultdict # decorators are fine
def d2(key):
return -key
d2[5] # yields -5
如果你不想把这个值添加到字典里以便下次调用,你可以使用一个
def __missing__(self, key): return self.default_factory(key)
它会在每次key: value
对没有被明确添加时调用默认工厂。
19
还有一个选择,前提是你不打算在字典里存储假值:
test.get('store') or run()
在Python中,or
运算符不会去计算那些不需要的参数(它会短路)
如果你需要支持假值,那么你可以使用get_or_run(test, 'store', run)
,其中:
def get_or_run(d, k, f):
sentinel = object() # guaranteed not to be in d
v = d.get(k, sentinel)
return f() if v is sentinel else v
10
可以查看dict.get()方法返回指针中的回答和评论进行讨论。你需要把这个问题分成两个步骤来解决。
你有以下几种选择:
如果你总是希望有一个默认值,并且想把它存储在字典里,可以使用一个带有可调用对象的
defaultdict
。使用条件表达式:
item = test['store'] if 'store' in test else run()
使用
try
/except
:try: item = test['store'] except KeyError: item = run()
使用
get
:item = test.get('store') if item is None: item = run()
还有这些方法的变体。
glglgl展示了一种子类化defaultdict
的方法,你也可以在某些情况下直接子类化dict
:
def run():
print "RUNNING"
return 1
class dict_nokeyerror(dict):
def __missing__(self, key):
return run()
test = dict_nokeyerror()
print test['a']
# RUNNING
# 1
只有在你总是希望字典有一些非标准行为时,子类化才真正有意义;如果你一般希望它像普通的dict
那样工作,只是在某个地方想要懒惰的get
,可以使用我提到的第二到第四种方法。