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()