检查列表中特定元素的更好方法 - Python

6
我正在使用try/except块来代替一堆andif/elif。我正在查看一个列表并替换某些元素,如果它具有x和x和x等。在我的项目中,我必须检查超过6个条件,这导致我使用了try/except.index(),如果元素不存在,它将抛出错误。
类比如下:
colors = ['red', 'blue', 'yellow', 'orange']

try:
    red_index = colors.index('red')
    blue_index = colors.index('blue')
    colors[red_index] = 'pink'
    colors[blue_index] = 'light blue'
except ValueError:
    pass
try:
    yellow_index = colors.index('yellow')
    purple_index = colors.index('purple')
    colors[yellow_index] = 'amarillo'
    colors[purple_index] = 'lavender'
except ValueError:
    pass

所以,如果colors数组不包含'purple''yellow',我就不想改变数组。
我对这种方法有点担心,因为它似乎滥用了try/except。但是与替代方案相比,它要短得多,因为无论如何我都必须获取元素的index,所以我想知道是否存在明显的问题,或者这是否足够疯狂,使其它开发人员会厌恶我。

len(set(colors) & set("purple yellow".split())) == 2 - Joran Beasley
当你说“更短”时,你的意思是代码行数还是时间效率? - alksdjg
使用 if ('red' in colors and 'blue' in colors): 而不是 try: 应该能够满足你的所有需求。 - Alea Kootz
@ lluvatar14,现在有几个回答您的问题。请您选择一个作为首选解决方案(通过单击其左侧的复选标记),以便关闭您的问题。 - Alea Kootz
5个回答

2

这并不疯狂;在Python中使用try/except是非常pythonic的 - 参见这个问题以获取更多讨论。

另一种方法是:

if 'red' in colours and 'blue' in colours:
    colour[colours.index('red')] = 'pink'
    # etc

与try/except相比的优势:

  1. 如果你喜欢简洁的代码,那么代码行数更少
  2. 更易读 - 任何未来的读者都能立即知道你的意思

与try/except相比的劣势:

  1. 速度慢一些(尽管只是微不足道的量),因为contains将会对元素进行自己的搜索。

除非你正在做某些需要极高时间效率的事情,否则我会更倾向于可读性。然而,如果你有其他原因,try/except也不是不能接受的。


谢谢@alksdjg,这个答案对我非常有用。我认为可读性在这里是必须的,但我会坚持使用try/except来避免使用ands。 - Iluvatar14
非常感谢,不过明确一下,我是在说try/except比if语句更不可读 - alksdjg
哦,抱歉,我有点傻,你确实说了那个。不过还是这样。 - Iluvatar14

2
您可以使用一个set。我们将使用issuperset, difference_update, 和 update,分别缩写为>=, -=, 和 |=
colors = {'red', 'blue', 'yellow', 'orange'}

if colors >= {'red', 'blue'}:
    colors -= {'red', 'blue'}
    colors |= {'pink', 'light blue'}
elif colors >= {'yellow', 'purple'}:
    colors -= {'yellow', 'purple'}
    colors |= {'amarillo', 'lavender'}

1

更新后的答案

您可能需要使用map()构建一个函数,如下所示:

def replace(sequence, replaceDict):
    for seekVal in replaceDict.keys():
        if seekVal not in sequence:
            return sequence #Not modified, as seek not found.
    replaceFunc = lambda item: replaceVal if item==seekVal else item
    for seekVal in replaceDict:
        replaceVal = replaceDict[seekVal]
        sequence = map(replaceFunc, sequence)
    return sequence

然后只需要运行:
colors = replace(colors, {'red' : 'pink', 'blue' : 'light blue'})

嗯,误解了问题。在更改之前需要满足多个要求。给我一分钟,我会重新写答案。 - Kal Zekdor

1

你的代码很接近了,但有一些有用的内置函数可以帮助:

colors = ['red', 'blue', 'yellow', 'orange']

if ('red' in colors and 'blue' in colors):
    red_index = colors.index('red')
    blue_index = colors.index('blue')
    colors[red_index] = 'pink'
    colors[blue_index] = 'light blue'

if ('yellow' in colors and 'purple' in colors):
    yellow_index = colors.index('yellow')
    purple_index = colors.index('purple')
    colors[yellow_index] = 'amarillo'
    colors[purple_index] = 'lavender'

这会创建逻辑门(需要同时存在两种颜色),这样只有在您想要执行时才会执行。
这是一个非常小的改变,但我认为它可以更好地处理您的错误情况。

1

您可以使用dict和列表推导式以更简单和更短的方式完成,如下所示:

colors = ['red', 'blue', 'yellow', 'orange']

# First define you replaces
replaces = {
    'red': 'ping',
    'blue': 'light blue',
    'yellow': 'amarillo',
    'purple': 'lavender'
}

# Then define the replacing function
def replace(key, replaces):
    return replaces.get(key) or key

# And then replace all the intended element
colors = [replace(el, replaces) for el in colors]

这段代码的作用是,对于每个元素,它会在字典中查找该元素,如果该元素在字典中(即需要被替换),则返回相应的替换值,否则,返回原始值。

接下来介绍条件语句,你可以像这样编写:

if 'purple' in colors and 'red' in colors:
    colors = [replace(el, {
            'yellow': 'amarillo',
            'purple': 'lavender'
        }) for el in colors]

...

并且对于任何其他条件也是一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接