Лучший способ проверить список на наличие определенных элементов — python

Я использую блоки try/except вместо блоков if/elif, у которых есть куча блоков and. Я просматриваю список и заменяю некоторые элементы, если в нем есть 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, поэтому я хотел бы знать, есть ли с этим вопиющие проблемы или это достаточно безумно, чтобы другие разработчики ненавидели меня за это.


person Iluvatar14    schedule 29.09.2015    source источник
comment
Что вы имеете в виду, когда говорите, что это намного «короче»? Строки кода или экономия времени?   -  person alksdjg    schedule 30.09.2015
comment
Использование if ('red' in colors and 'blue' in colors): вместо try: должно иметь все необходимое.   -  person Alea Kootz    schedule 30.09.2015
comment
@ lluvatar14 Теперь есть несколько ответов на ваш вопрос. Не могли бы вы выбрать одно из предпочтительных решений (щелкнув галочку слева от него), чтобы ваш вопрос можно было закрыть?   -  person Alea Kootz    schedule 30.09.2015


Ответы (5)


Это не сумасшествие; 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 выполнит собственный поиск элемента.

Если вы не делаете что-то, что требует, чтобы это было чрезвычайно эффективным по времени, я бы предпочел удобочитаемость. Тем не менее, попытка/исключение не является непростительной, если у вас есть другие причины для этого.

person alksdjg    schedule 29.09.2015
comment
Спасибо @alksdjg, этот ответ наиболее полезен для меня. Я думаю, что удобочитаемость здесь обязательна, но я буду придерживаться try/except, чтобы избежать and. - person Iluvatar14; 30.09.2015
comment
Большое спасибо, хотя, чтобы быть ясным, я говорю, что оператор try/except менее читаем, чем оператор if. - person alksdjg; 30.09.2015
comment
Ой, извините, я тупой, вы это сказали. Тем не менее. - person Iluvatar14; 30.09.2015

Вы можете использовать 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'}
person Peter Wood    schedule 29.09.2015

Ваш код близок, но есть несколько полезных встроенных функций, которые помогут:

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'

Это создает логические ворота (должны присутствовать оба цвета), чтобы они выполнялись только тогда, когда вы этого хотите.

Это очень небольшое изменение, но я думаю, что оно лучше справится с вашими случаями ошибок.

person Alea Kootz    schedule 29.09.2015

На самом деле вы могли бы пойти более простым и гораздо более коротким путем, используя 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]

...

И так же для любых других условий.

person bagrat    schedule 29.09.2015

Обновленный ответ

Вероятно, вы захотите создать функцию с помощью 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'})
person Kal Zekdor    schedule 29.09.2015
comment
Мм, неправильно понял вопрос. Перед изменением необходимо выполнить несколько требований. Дай мне минуту, я перепишу ответ. - person Kal Zekdor; 30.09.2015