【问题标题】:Is there a pythonic way to check list elements, and stop at end of list (without an error)?有没有一种pythonic方法来检查列表元素,并在列表末尾停止(没有错误)?
【发布时间】: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

【问题讨论】:

    标签: python-2.7 loops exit


    【解决方案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 的定义的观点。由于主要是自学成才,这是我遇到的一个常见问题。你给出的例子读起来好多了,我想我会重组我用来模拟这个的函数。这将是一些工作,但我以后可能会为此感谢自己。感谢您为我展示这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 1970-01-01
    • 2013-09-10
    相关资源
    最近更新 更多