Slice: примеры (PYTHON)

Использование и возможности функции slice в Python
Раздел: Встроенные функции, Создание срезов
slice(start[, stop[, step]]): slice

Описание функции slice

Функция slice в Python создает объект среза, который может использоваться для извлечения части последовательности (строки, списка, кортежа). Этот объект определяет диапазон индексов и удобен для многократного использования одного и того же среза.

Функция вызывается с одним, двумя или тремя аргументами: slice(stop), slice(start, stop) или slice(start, stop, step).

Аргументы:

  • start (необязательный): Начальный индекс среза (включительно). По умолчанию равен 0. Может быть отрицательным.
  • stop (обязательный для двухаргументной формы, опциональный для одноаргументной): Индекс, на котором срез заканчивается (исключительно). Может быть отрицательным.
  • step (необязательный): Шаг для выбора элементов. По умолчанию равен 1 (все элементы подряд). Может быть отрицательным для среза в обратном порядке.

Возвращаемое значение: Объект типа slice, который не содержит сами данные, а только правила их извлечения. Этот объект можно передавать в квадратные скобки для получения среза последовательности.

Функция часто используется, когда нужно многократно применять один и тот же срез к разным последовательностям или когда параметры среза вычисляются динамически.

Примеры использования slice

Простое создание объекта среза и его применение:

my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Создание объекта среза от индекса 2 до 5
s = slice(2, 5)
print(my_list[s])
[2, 3, 4]

Использование всех аргументов:

s = slice(1, 8, 2)
print(my_list[s])
[1, 3, 5, 7]

Отрицательные значения:

s = slice(-5, -1)
print(my_list[s])
[5, 6, 7, 8]

Обратный порядок с помощью отрицательного шага:

s = slice(None, None, -1)
print(my_list[s])
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Срез с одним аргументом (stop):

s = slice(5)
print(my_list[s])
[0, 1, 2, 3, 4]

Альтернативные способы в Python

Непосредственное использование синтаксиса квадратных скобок [start:stop:step] является более распространенной и читаемой альтернативой для разовых операций.

my_list = [0, 1, 2, 3, 4, 5]
print(my_list[1:4:2])  # Прямой синтаксис

# Эквивалентно:
s = slice(1, 4, 2)
print(my_list[s])
[1, 3]
[1, 3]

Также существуют функции itertools.islice() для ленивого среза итераторов и работа с numpy массивами, которая предоставляет расширенные возможности индексации.

Выбор инструмента: Синтаксис квадратных скобок используется для простых и разовых срезов. Функция slice() полезна, когда параметры среза вычисляются заранее или когда один срез применяется к нескольким последовательностям. itertools.islice() нужен для работы с итераторами, когда не требуется загрузка всех данных в память.

Аналоги в других языках программирования

JavaScript: Метод slice() для массивов и строк возвращает новый массив/строку. Параметры: start и end (необязательный). Отрицательные индексы отсчитываются с конца.

let arr = [0,1,2,3,4];
console.log(arr.slice(1,4)); // [1,2,3]
console.log(arr.slice(2));   // [2,3,4]
[1, 2, 3]
[2, 3, 4]

PHP: Функция array_slice() для массивов. Параметры: массив, offset, length (необязательный), preserve_keys (необязательный).

$arr = [0,1,2,3,4];
print_r(array_slice($arr, 1, 3)); // [1,2,3]
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

Java: Метод substring() для строк или subList() для списков. Работают с начальным и конечным индексами.

String str = "Hello";
System.out.println(str.substring(1,4)); // "ell"

List list = Arrays.asList(0,1,2,3,4);
System.out.println(list.subList(1,4)); // [1,2,3]
ell
[1, 2, 3]

SQL (PostgreSQL): Используется конструкция OFFSET и LIMIT или ROW_NUMBER() для выборки диапазона строк.

SELECT * FROM table_name
ORDER BY id
OFFSET 5 ROWS
FETCH NEXT 10 ROWS ONLY;
(результат запроса)

C#: Метод Substring() для строк и метод GetRange() для списков. В C# 8.0 появился синтаксис диапазонов (range) [start..end], схожий с Python.

int[] arr = {0,1,2,3,4};
var slice = arr[1..4]; // {1,2,3}

string str = "Hello";
var sub = str[1..4]; // "ell"
[1, 2, 3]
ell

Lua: Нет встроенной функции. Обычно используют циклы или пишут собственную функцию для создания таблицы-среза.

Go: Используется синтаксис среза (slice) для массивов и срезов: arr[start:end]. End является эксклюзивным.

arr := []int{0,1,2,3,4}
slice := arr[1:4] // [1 2 3]
[1 2 3]

Отличия от Python: в большинстве языков аналоги работают только с двумя параметрами (start, stop) и не имеют прямого аналога параметра step, как в Python. Исключение - синтаксис в C# 8.0 и Go, который похож, но без шага.

Частые ошибки при работе со slice

Передача неправильного типа аргументов.

try:
    s = slice("1", "4")
    my_list = [0,1,2,3,4]
    print(my_list[s])
except TypeError as e:
    print(f"Ошибка: {e}")
Ошибка: slice indices must be integers or None or have an __index__ method

Путаница между объектом среза и его результатом. Объект slice сам по себе не содержит данных.

s = slice(2,5)
print(s)  # Это объект, а не данные
print(type(s))
slice(2, 5, None)

Использование среза за пределами допустимых индексов последовательности. Функция не вызывает ошибку, а возвращает пустую последовательность или обрезанный результат.

my_list = [0,1,2]
s = slice(10, 20)
print(my_list[s])  # Нет ошибки
[]

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

Изменения в последних версиях Python

В Python 3.x не было значительных изменений в работе функции slice(). Ее поведение остается стабильным на протяжении многих версий.

Однако, начиная с Python 3.9, объекты slice получили атрибуты .indices(length), которые уже существовали ранее. Этот метод принимает длину последовательности и возвращает кортеж (start, stop, step), приведенные к допустимым индексам для данной длины, что упрощает ручные вычисления.

s = slice(2, 10, 2)
print(s.indices(5))  # Для последовательности длины 5
(2, 5, 2)

Этот метод полезен при реализации собственных классов, поддерживающих срезы.

Расширенные примеры применения

Использование slice для нарезки многомерных структур (например, списка списков).

Пример python
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
row_slice = slice(0, 2)  # Первые две строки
col_slice = slice(1, 3)  # Второй и третий столбец
result = [row[col_slice] for row in matrix[row_slice]]
print(result)
[[2, 3], [5, 6]]

Динамическое создание среза на основе условий.

Пример python
def get_dynamic_slice(data_length, percent):
    # Возвращает срез для последних percent% данных
    start = int(data_length * (1 - percent / 100))
    return slice(start, None)

data = list(range(100))
s = get_dynamic_slice(len(data), 10)  # Последние 10%
print(data[s][:5])  # Первые 5 элементов из последних 10%
[90, 91, 92, 93, 94]

Использование slice в качестве ключа для словаря (объекты slice хешируемы).

Пример python
cache = {}
data_source = [0,1,2,3,4,5,6,7,8,9]

s = slice(2, 6)
if s not in cache:
    cache[s] = data_source[s]

print(cache.get(slice(2,6)))
print(cache.get(slice(3,7)))
[2, 3, 4, 5]
None

Применение одного объекта slice к разным типам последовательностей.

Пример python
s = slice(1, -1)
string_data = "Hello World"
list_data = [10, 20, 30, 40, 50]
tuple_data = (1.1, 2.2, 3.3, 4.4)

print(string_data[s])
print(list_data[s])
print(tuple_data[s])
ello Worl
[20, 30, 40]
(2.2, 3.3)

Создание среза с помощью slice для имитации операции reversed().

Пример python
def custom_reversed(sequence):
    return sequence[slice(None, None, -1)]

print(custom_reversed([1,2,3]))
print(custom_reversed("abc"))
[3, 2, 1]
cba

Использование метода indices для обработки среза в пользовательском классе.

Пример python
class MySequence:
    def __init__(self, data):
        self.data = data
    def __getitem__(self, key):
        if isinstance(key, slice):
            start, stop, step = key.indices(len(self.data))
            return [self.data[i] for i in range(start, stop, step)]
        else:
            return self.data[key]

obj = MySequence([0,10,20,30,40,50])
print(obj[2:5])  # Использует slice
print(obj[slice(1, None, 2)])
[20, 30, 40]
[10, 30, 50]

питон slice function comments

En
Slice Create slice object