检查元素存在于数组中


70

在PHP中,有一个函数被调用isset()来检查是否存在某种东西(如数组索引)并具有一个值。Python怎么样?

我需要在数组上使用它,因为有时会出现“ IndexError:列表索引超出范围”。

我想我可以使用try / catching,但这是不得已的方法。


2
EAFP:寻求宽恕比获得许可要容易。
— NullUserException 2011年

4
您的问题询问有关PHP数组(在Python中大致为字典),但您的错误消息引用了列表操作。代码示例可能会消除一些混乱。
— David K. Hess

1
又:“不得已”。“最后还原”是完全不同的东西。
— 阿玛丹

问题是我正在编写一个脚本,以将从CSV导出的Google文档电子表格矩阵转换为其他格式。有时,如果最后一列(最右边)为空,则Google会忽略指示最后一列的最后一个逗号。
— 乔尼

Answers:


113

跳跃前先看看(LBYL):

if idx < len(array):
    array[idx]
else:
    # handle this

寻求宽容比获得许可更容易(EAFP):

try:
    array[idx]
except IndexError:
    # handle this

在Python中,EAFP似乎是最受欢迎的样式。它通常更可靠,并且避免了一整类错误(检查时间与使用时间)。在所有其他条件相同的情况下,建议使用try/except版本-不要将其视为“万不得已”。

此摘录来自上面链接的官方文档,并使用try / except进行流量控制:

这种通用的Python编码风格假定有效键或属性的存在,并在假定被证明为假的情况下捕获异常。这种干净快捷的样式的特点是存在许多try和except语句。


有时您只想弄清楚一个索引是否存在或它是哪个索引(当然,python缺少switch语句)。另外,我不确定这是否是比赛条件,但我不是专家。当做某件事的行为产生某种循环疯狂的可能性时,这不是种族条件吗?如果我只是检查索引是否存在,那应该不会影响线程的竞争性。我想检查后的操作可能会影响其他线程。
— ekeyser 2014年

1
另一方面(OTOH),EAFP存在问题,因为当发生错误时,它需要遍历调用堆栈。
— 达斯(Garth Egregious)

48

EAFP对阵LBYL

我了解您的难题,但是Python不是PHP,并且比Permission(简称EAFP)更容易被人们寻求宽恕的编码风格是Python中的一种常见编码风格。

请参阅源(来自文档):

EAFP-寻求宽恕比获得许可更容易。这种通用的Python编码风格假定有效键或属性的存在,并在假定被证明为假的情况下捕获异常。这种干净快捷的样式的特点是存在许多try和except语句。该技术与许多其他语言(例如C)通用的LBYL风格形成对比。

因此,基本上,在这里使用try-catch语句并不是万不得已。这是一种常见的做法。

Python中的“数组”

PHP具有关联和非关联数组,Python具有列表,元组和字典。列表类似于非关联的PHP数组,字典类似于关联的PHP数组。

如果要检查“数组”中是否存在“键”,则必须首先确定它在Python中的类型,因为当“键”不存在时它们会引发不同的错误:

>>> l = [1,2,3]
>>> l[4]

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    l[4]
IndexError: list index out of range
>>> d = {0: '1', 1: '2', 2: '3'}
>>> d[4]

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    d[4]
KeyError: 4

并且,如果您使用EAFP编码样式,则应适当地捕获这些错误。

LBYL编码样式-检查索引的存在

如果您坚持使用LBYL方法,则可以为您提供以下解决方案:

  • 对于列表,只需检查长度,如果存在,possible_index < len(your_list)则your_list[possible_index]存在,否则不存在:

    >>> your_list = [0, 1, 2, 3]
    >>> 1 < len(your_list) # index exist
    True
    >>> 4 < len(your_list) # index does not exist
    False
    
  • 对于字典,您可以使用in关键字,如果possible_index in your_dict,那么your_dict[possible_index]存在,否则它不会:

    >>> your_dict = {0: 0, 1: 1, 2: 2, 3: 3}
    >>> 1 in your_dict # index exists
    True
    >>> 4 in your_dict # index does not exist
    False
    

有帮助吗?


好答案。有什么原因为什么未定义的属性或索引在Python中根本不会返回asundefined或bool false?其他语言解释器会在这些事件上返回,我很好奇Python为什么没有。
— 65Fbef05 '02

@ 65Fbef05:我相信这是一个设计决定,但实际上您可以做到my_dict.get('some_index', False),例如,您不受限制。False当您尝试从字典中获取某些条目(如果该条目不存在时),Python还应该真正返回吗?我相信不会,因为如果存储False和不存储某些特定键的任何内容都会产生相同的结果,那么很难在代码中找到问题。我认为,当您想要的东西不在这里并且您没有明确表示要处理这种情况时(例如通过使用get()),抛出错误是个好主意。
— 塔德克2012年

1
我认为返回False比抛出错误更有用的一种特定情况是,当您不确定索引是否存在时,例如在可选的CLI参数中,应用程序逻辑的实际异常仅在存在值时发生。
— 65Fbef05 '02

@ 65Fbef05:当某些特定的CLI参数存在或不存在时,无需引发异常,您可以只使用argparsemodule。而且我不记得有任何一种语言在找到其值时实际上会引发错误。或我误解了您的评论;)无论如何,正如我所说,您可以通过使用类似于的方式来支持默认参数cli_args.get('option1', False)。
— 塔德克2012年

发现值存在时,我并不一定要“抛出错误”。我的意思是或多或少比标准例行程序“有所作为”。
— 65Fbef05 '02

15
`e` in ['a', 'b', 'c']  # evaluates as False
`b` in ['a', 'b', 'c']  # evaluates as True

编辑:随着澄清,新的答案:

请注意,PHP数组与Python的数组有很大不同,它将数组和字典组合为一个混乱的结构。Python数组始终具有从0到的索引len(arr) - 1,因此您可以检查索引是否在该范围内。try/catch不过,这是用Python很好的方法。

如果您要询问PHP“数组”(Python的dict)的哈希功能,那么我以前的回答仍然是这样:

`baz` in {'foo': 17, 'bar': 19}  # evaluates as False
`foo` in {'foo': 17, 'bar': 19}  # evaluates as True

嗯?我在问数组中是否存在索引元素,而不是数组中是否存在值。
— 强尼

@Jonny:这是PHP和Python之间的区别之一。PHP数组是Python中的Dictionary。在python中,列表仅具有整数索引。
— unholysampler 2011年


0

您也许可以使用内置函数dir()来产生与PHP类似的行为isset(),例如:

if 'foo' in dir():  # returns False, foo is not defined yet.
    pass

foo = 'b'

if 'foo' in dir():  # returns True, foo is now defined and in scope.
   pass

dir()返回当前作用域中的名称列表,有关更多信息,请参见:http : //docs.python.org/library/functions.html#dir。


0

在这种情况下,如果您要求宽恕,在Python中您可能会有些意外。

在这里,try-except不是正确的范例。

如果您不小心得到了负指数,您会感到惊讶。

更好的解决方案是自己提供测试功能:

def index_in_array(M, index):
    return index[0] >= 0 and index[1] >= 0 and index[0]< M.shape[0] and index[1] < M.shape[1]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.