似乎即使密钥存在于字典中,也会调用回退。这是预期的行为吗?怎么解决它?
>>> i = [1,2,3,4]
>>> c = {}
>>> c[0]= 0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop from empty list
答案 0 :(得分:1)
执行c.get(0, i.pop())
时,i.pop()
部分会在之前评估,它返回的结果会传递给c.get(...)
。这就是因为如果列表i
由于先前的.pop()
调用而为空而出现错误的原因。
为了解决这个问题,您应该在尝试从中弹出元素之前检查列表是否为空,或者只是尝试捕获可能的异常:
if not i:
# do not call do i.pop(), handle the case in some way
default_val = i.pop()
或
try:
c.get(0, i.pop())
except IndexError:
# gracefully handle the case in some way, e.g. by exiting
default_val = i.pop()
第一种方法称为LBYL(&#34;在你跳跃之前看看&#34; ),而第二种方法称为EAFP(&#34;更容易要求宽恕而不是许可&#34; )。后者在Python中通常是首选,并且被认为更加Pythonic,因为代码不会被大量的安全检查混乱,尽管LBYL方法也有其优点,并且可以像可读的一样(依赖于用例)。 / p>
答案 1 :(得分:1)
这是预期的结果,因为您直接调用>>> query = "String: {} Number: {}"
>>> param = ['text', 1]
>>> query.format(*(repr(i) for i in param))
"String: 'text' Number: 1"
之前调用的i.pop()
。
答案 2 :(得分:1)
在字典检查密钥是否存在之前,确实会对dict.get
的默认参数进行评估。事实上,它甚至在调用get
方法之前进行了评估!您的get
来电与此相同:
default = i.pop() # this happens unconditionally
c.get(0, default)
default = i.pop() # this one too
c.get(0, default)
#...
如果要指定仅用于填充缺少的字典值的可调用对象,则可能需要使用collections.defaultdict
。它需要一个可调用的,完全按照这种方式使用:
c = defaultdict(i.pop) # note, no () after pop
c[0] = 0
c[0] # use regular indexing syntax, won't pop anything
请注意,与get
调用不同,调用返回的值实际上会在之后存储在字典中,这可能是不合需要的。
答案 3 :(得分:1)
这是预期的行为,因为i.pop()
是在c.get(...)
之前计算的表达式。想象一下,如果不是这样的话会发生什么。你可能有这样的事情:
def myfunction(number):
print("Starting work")
# Do long, complicated setup
# Do long, complicated thing with number
myfunction(int('kkk'))
您何时会对int('kkk')
进行评估?只要myfunction()
使用它(在参数之后)就可以了吗?在漫长而复杂的设置之后,它最终将具有ValueError。如果您要说x = int('kkk')
,您何时会期望ValueError?首先评估右侧,并立即发生ValueError。 x
未定义。
有几种可能的解决方法:
c.get(0) or i.pop()
这可能适用于大多数情况,但如果c.get(0)
可能返回不是None
的Falsey值,则无法工作。更安全的方式是更长一点:
try:
result = c[0]
except IndexError:
result = i.pop()
当然,我们喜欢EAFP(更容易请求宽恕而不是许可),但您可以请求许可:
c[0] if 0 in c else i.pop()
(致@soon的信用)
答案 4 :(得分:1)
除了使用 if ... else ... 之外,没有其他方法可以解决此问题!
在您的情况下,此代码将起作用:
c[0] if 0 in c else i.pop()
答案 5 :(得分:0)
在调用get函数之前,都会计算两个参数。因此,在所有调用中,即使存在密钥,列表的大小也会减少1。
尝试类似的东西 如果c.has_key(0): 打印c [0] 其他: 打印i.pop()