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 для нарезки многомерных структур (например, списка списков).
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]]
Динамическое создание среза на основе условий.
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 хешируемы).
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 к разным типам последовательностей.
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().
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 для обработки среза в пользовательском классе.
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]