有没有一种pythonic方法来检查列表元素,并在列表末尾停止(没有错误)?

Posted

技术标签:

【中文标题】有没有一种pythonic方法来检查列表元素,并在列表末尾停止(没有错误)?【英文标题】:Is there a pythonic way to check list elements, and stop at end of list (without an error)? 【发布时间】:2016-08-25 04:28:00 【问题描述】:

我有一个复杂的系统后端,但我试着做一个简单的例子,所以你知道我在说什么。

基本上我有一个 ID 列表,用户(通过 gui)将在这个列表中循环生成 ID。

在某些时候,他们想要检查并修复所有他们搞砸或跳过的问题(这些都将具有相同的 ID);这就是我有问题的地方。

我已经写了一些可以做到这一点的东西(检查列表是否有错误的 ID),但问题是一旦它到达列表的末尾,就会引发索引错误。我想干净地退出while循环,而是退出函数

def nextID():
    '''
        increment counter until we find a junk ID
    '''
    global tindx

    skips = 0
    while IDs[tindx] != 'junk_id' and tindx != len(IDs):
        print 'This ID is good: %s' %IDs[tindx]
        skips+=1
        tindx+=1    
    print 'Skipped %i IDs' %(skips), 'tindx is now',tindx

这被设计成(又是一个巨大的简化)以下列方式使用

tindx = 0

IDs = ['abc','bcd','cde','junk_id','junk_id','def','efg','junk_id','fgh','ghi']

# This is all hadled with in an interactive GUI
# User wants next ID
nextID()
# User changes ID
IDs[tindx] = 'good_id!'
# User wants next ID
nextID()
# User changes ID
IDs[tindx] = 'another_good_id'
# etc .... 

我知道如果我切换while循环条件的顺序,它将避免自动IndexError,但用户不会知道他们已经到达列表的末尾并会尝试更改ID(得到同样的错误)。

我想告诉用户他们完成了运行save_IDs() 函数,然后退出程序。这边重新设计软件,有没有比加入下面if条件更好的办法

while  ...

   if tindx == len(IDs):
      print 'you\'re done'
      save_IDs()
      return None

【问题讨论】:

【参考方案1】:

正如您所提到的,您确实需要在 while 上切换参数:

while tindx != len(IDs) and IDs[tindx] != 'junk_id':
    ...

否则它会先尝试访问IDs[tindx],然后检查是否无效。

对于这个问题,您可以让 nextID 在到达末尾时返回新索引或 None:

def nextID(last_offset):
    offset = last_offset

    while offset < len(IDs) and IDs[offset] != 'junk_id'
        offset += 1

    if offset >= len(IDs):
        return None

    if offset > last_offset:
        print("Skipped %d IDs" % (offset - last_offset))

    return offset

然后使用它:

current_offset = 0
while doing things:
    current_offset = nextID(current_offset)
    if current_offset == None:
        # All done.
        break

    print("New offset: %d" % (offset))

    if user changes id:
        IDs[current_offset] = 'good_id!'
    else:
        # If the user didn't change the ID for whatever reason,
        # you'll need to manually increment current_offset.
        current_offset += 1

print("All done, saving..")
saveIDs()

如果您在 GUI 内的回调中,那么您可能会有更多类似这样的内容:

def userChangedID(new_value):
    global current_offset

    IDs[current_offset] = new_value
    current_offset = nextID(current_offset)

    if current_offset == None:
        finish()

def userSkippedID():
    global current_offset

    current_offset = nextID(current_offset + 1)

    if current_offset == None:
        finish()

def finish():
    global finished

    finished = True
    print("All done, saving...")
    saveIDs()

理想情况下,一个方法应该具有尽可能少的副作用,因为它需要做它应该做的事情。

在原始代码中,nextID() 不仅是“寻找下一个 ID”,它还改变了整个进程的状态。

从开发人员的角度来看,这会造成相当大的误导,他们可能只是希望 nextID() 找到并返回下一个 ID。

【讨论】:

感谢您关于我对 nextID 的定义的观点。由于主要是自学成才,这是我遇到的一个常见问题。你给出的例子读起来好多了,我想我会重组我用来模拟这个的函数。这将是一些工作,但我以后可能会为此感谢自己。感谢您为我展示这一点。

以上是关于有没有一种pythonic方法来检查列表元素,并在列表末尾停止(没有错误)?的主要内容,如果未能解决你的问题,请参考以下文章

检查列表是不是包含与某些东西不同的元素[重复]

Python:检查列表中至少一个正则表达式是不是与字符串匹配的优雅方法

Python基础-列表

有没有一种 Pythonic 方法来检查操作系统是不是是 64 位 Ubuntu?

python3检查列表、元组、字符串中的重复元素

在 Python 中拒绝列表的快速方法