Python 奇怪的行为
似乎即使字典中存在密钥,也会调用回退。这是故意的行为吗?如何解决这个问题Python 奇怪的行为,python,dictionary,Python,Dictionary,似乎即使字典中存在密钥,也会调用回退。这是故意的行为吗?如何解决这个问题 >>> 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 >>>
>>> 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
>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())
回溯(最近一次呼叫最后一次):
文件“”,第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()
或
第一种方法称为LBYL(“三思而后行”),而第二种方法称为EAFP(“请求原谅比允许更容易”)。后者在Python中通常是首选的,并且被认为是更具Python风格的,因为代码不会因为大量的安全检查而变得混乱,尽管LBYL方法也有其优点,并且可以同样可读(依赖于用例)。当执行c.get(0,i.pop())
时,i.pop()
part在返回的结果传递给c.get(…)
之前进行求值。这就是如果列表i
由于前面的.pop()
调用而为空时出现错误的原因
要解决此问题,您应该在尝试从列表中弹出元素之前检查列表是否为空,或者只是尝试捕获可能的异常:
if not i:
# do not call do i.pop(), handle the case in some way
default_val = i.pop()
或
第一种方法称为LBYL(“三思而后行”),而第二种方法称为EAFP(“请求原谅比允许更容易”)。后者在Python中通常是首选的,并且被认为更具Python风格,因为代码不会因为大量的安全检查而变得杂乱无章,尽管LBYL方法也有其优点,并且可以同样可读(依赖于用例)。这是预期的结果,因为您直接调用了
i.pop()
在c.get()
之前被调用这是预期的结果,因为您正在直接调用i.pop()
,它在c.get()
之前被调用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
调用不同,可调用函数返回的值实际上会在调用后存储在字典中,这可能是不需要的。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
调用不同,可调用函数返回的值实际上会在调用后存储在字典中,这可能是不需要的。这是预期的行为,因为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
的错误值,则这将不起作用。更安全的方法是更长一点:
try:
result = c[0]
except IndexError:
result = i.pop()
当然,我们喜欢EAFP(请求原谅比请求许可更容易),但您可以请求许可:
c[0] if 0 in c else i.pop()
(归功于@soon)这是预期的行为,因为
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
的错误值,则这将不起作用。更安全的方法是更长一点:
try:
result = c[0]
except IndexError:
result = i.pop()
当然,我们喜欢EAFP(请求原谅比请求许可更容易),但您可以请求许可:
c[0] if 0 in c else i.pop()
(归功于@soon)在调用get函数之前对这两个参数进行求值。因此,在所有调用中,即使存在键,列表的大小也会减少1 试试像这样的东西 如果c.具有_键(0): 打印c[0] 其他: 打印i.pop()