Почему в списке нет безопасного метода "получить", как словарь?

Почему в списке нет безопасного метода get, такого как словарь?

>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'

>>> l = [1]
>>> l[10]
IndexError: list index out of range

Ответ 1

В конечном счете он, вероятно, не имеет безопасного метода .get, потому что dict является ассоциативной коллекцией (значения связаны с именами), где неэффективно проверять наличие ключа (и вернуть его значение) без бросая исключение, в то время как супер-тривиально избегать исключений, обращающихся к элементам списка (поскольку метод len очень быстрый). Метод .get позволяет вам запрашивать значение, связанное с именем, а не напрямую обращаться к 37-му элементу в словаре (что больше похоже на то, что вы запрашиваете в своем списке).

Конечно, вы можете легко реализовать это самостоятельно:

def safe_list_get (l, idx, default):
  try:
    return l[idx]
  except IndexError:
    return default

Вы можете даже обезвредить его в конструкторе __builtins__.list в __main__, но это будет менее распространенное изменение, поскольку большинство кода его не использует. Если вы просто хотели использовать это со списками, созданными вашим собственным кодом, вы могли бы просто подклассом list и добавить метод get.

Ответ 2

Это работает, если вы хотите, чтобы первый элемент, например my_list.get(0)

>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'

Я знаю, что это не то, что вы просили, но может помочь другим.

Ответ 3

Вместо использования .get, использование этого метода должно быть в порядке для списков. Просто разница в использовании.

>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'

Ответ 4

Возможно, потому, что это просто не имело смысла для семантики списка. Однако вы можете легко создать свой собственный подклассом.

class safelist(list):
    def get(self, index, default=None):
        try:
            return self.__getitem__(index)
        except IndexError:
            return default

def _test():
    l = safelist(range(10))
    print l.get(20, "oops")

if __name__ == "__main__":
    _test()

Ответ 5

Попробуйте следующее:

>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'

Ответ 6

Лучшее, что вы можете сделать, это преобразовать список в dict и затем получить доступ к нему с помощью метода get:

>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')

Ответ 7

Кредиты jose.angel.jimenez


Для поклонников "oneliner"...


Если вам нужен первый элемент списка или если вы хотите значение по умолчанию, если список пуст, попробуйте:

liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)

возвращает a

и

liste = []
value = (liste[0:1] or ('default',))[0]
print(value)

возвращает default


Примеры для других элементов...

liste = ['a', 'b', 'c']
print(liste[0:1])  # returns ['a']
print(liste[1:2])  # returns ['b']
print(liste[2:3])  # returns ['c']

С отключением по умолчанию...

liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0])  # returns a
print((liste[1:2] or ('default',))[0])  # returns b
print((liste[2:3] or ('default',))[0])  # returns c

Протестировано с помощью Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)

Ответ 8

Итак, я сделал еще несколько исследований в этом, и, оказывается, нет ничего конкретного для этого. Я взволновался, когда нашел list.index(значение), он возвращает индекс указанного элемента, но нет ничего для получения значения по определенному индексу. Поэтому, если вы не хотите использовать решение safe_list_get, которое, я думаю, довольно хорошо. Вот некоторые 1 лайнер, если операторы, которые могут выполнить задание для вас, в зависимости от сценария:

>>> x = [1, 2, 3]
>>> el = x[4] if len(x) == 4 else 'No'
>>> el
'No'

Вы также можете использовать None вместо "No", что имеет больше смысла.:

>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None

Также, если вы хотите просто получить первый или последний элемент в списке, это работает

end_el = x[-1] if x else None

Вы также можете включить их в функции, но мне все еще понравилось решение для исключения IndexError. Я экспериментировал с уменьшенной версией решения safe_list_get и сделал его немного проще (без дефолта):

def list_get(l, i):
    try:
        return l[i]
    except IndexError:
        return None

Не проверяйте, что быстрее.

Ответ 9

Словари предназначены для поиска. Имеет смысл спросить, существует ли запись или нет. Списки обычно повторяются. Не часто возникает вопрос, существует ли L [10], но если длина L равна 11.

Ответ 10

Однострочные вентиляторы могут использовать % если нужен круговой характер:

value = l[index] if abs(index)<len(l) else l[index%len(l)]

Ответ 11

Лучший способ убедиться, что вы не получили ошибку:

for i in list:
    do_stuff(i)

если список пуст, do_stuff не будет выполнен.

Ответ 12

Ваш usecase, в основном, имеет значение только при создании массивов и матриц фиксированной длины, чтобы вы знали, как долго они находятся перед рукой. В этом случае вы обычно также создаете их перед тем, как вручную заполнить их None или 0, так что фактически любой индекс, который вы будете использовать, уже существует.

Вы могли бы сказать следующее: мне очень часто нужно .get() в словарях. После десяти лет работы программистом на полный рабочий день, я не думаю, что мне когда-либо понадобилось это в списке.:)