Почему `for x в списке [None: None]:` work?

У меня есть script, который пытается прочитать начальную и конечную точку для подмножества через двоичный поиск, затем эти значения используются для создания среза для дальнейшей обработки.

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

#! /usr/bin/env python
list = [1,2,3,4,5,6,7,8,9,10]
for x in list[None:None]:
  print x

Кто-нибудь знает, почему был сделан выбор, чтобы увидеть list[None:None] просто как list[:], по крайней мере, то, что я думаю, что это происходит (исправьте меня, если я ошибаюсь). Я лично подумал бы, что в таком случае желательно было бы выбрасывать TypeError.

Ответ 1

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

None - это значение по умолчанию, потому что вы можете использовать отрицательный шаг, после чего изменяется начальная и конечная позиции по умолчанию. Сравните list[0:len(list):-1] с list[None:None:-1], например.

Python использует None для значения, не указанного в стандартной библиотеке; это не исключение.

Обратите внимание: если ваш класс реализует object.__getitem__ hook, вы получите переданный объект slice() с атрибутами start, end и stride, установленными на None:

>>> class Foo(object):
...     def __getitem__(self, key):
...         print key
... 
>>> Foo()[:]
slice(None, None, None)

Так как Foo() даже не реализует __len__, использующий по умолчанию использование None, здесь вполне логично.

Ответ 2

Я также считаю, что list[None:None] интерпретируется как list[:]. Это удобное поведение, потому что вы можете сделать что-то вроде этого:

return list[some_params.get('start'):some_params.get('end')]

Если раскладка списка не будет работать с None, вам нужно будет проверить, были ли start и end None сами:

if some_params.get('start') and some_params.get('end'):
    return list[some_params.get('start'):some_params.get('end')]
elif some_params.get('start'):
    return list[some_params.get('start'):]
elif end:
    return list[:some_params.get('end')]
else:
    return list[:]

К счастью, это не относится к Python:).

Ответ 3

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

def f(p=None):
    if f is None:
        f = some_default_value()

Я думаю, это делает выбор понятным: используйте None, вы можете сказать slicer использовать его значения по умолчанию.