Основи індексації та зрізів у Python
Всі стикаються з індексами на ранніх стадіях освоєння мови, як правило, при вивченні списків. Ймовірно, ви й так знаєте, що індексація у Python починається з нуля. У нас є список movies, тоді операція movies[0] поверне перший елемент списку.
Так, для новачків рахувати від нуля до дев'яти при роботі зі списком із десяти елементів спочатку здається трохи дивним. Python у цьому не унікальний — у більшості мов програмування реалізовано такий самий підхід (C, C++, Java, C# та JavaScript).
Варто обговорити не те, чим індексація у Python схожа на інші мови, а чим від них відрізняється. Наприклад:
- Вона майже ніколи не використовується у циклах. Так, ми можемо перебирати індекси елементів об'єкта в циклі for замість перебору власне елементів, але це норма.
- Можна використовувати негативні індекси, вони починаються із -1. -1 повертає останній елемент, -2 повертає передостанній тощо.
- Для отримання відразу кількох елементів можна використовувати розширену форму індексації. зрізи. Використовуючи зрізи у поєднанні з негативними індексами, можна, наприклад, розгорнути послідовність. Можна також вказувати крок зрізу для складання гнучких правил вилучення потрібних елементів.
Якщо ви новачок у Python, і вам поки що не знайомі ці концепції, то в цій статті ми розглянемо кілька практичних прикладів.
Проста пряма індексація
Давайте почнемо з кількох простих прикладів прямої індексації, використовуючи список, кортеж та рядок. Як показано нижче, індекс - це число, укладене у квадратні дужки, яке ми ставимо після складеного об'єкта.
numbers = [42, 1941, 1066, 1969] indexes = "Все дуже просто!" names = ("Оруелл", "Хакслі", "Зам'ятін") print(numbers[0]) # 42 last_index = len(indexes) - 1 print(indexes[last_index]) # ! print(f"Нас чекає майбутнє, як у книгах.") # Нас чекає майбутнє, як у книгах Хакслі.
Знову ж таки, у всіх випадках індекс першого елемента дорівнює нулю, а останнього — довжина об'єкта мінус одиниця. Використання індексу за межами цього діапазону призведе до того, що Python видасть помилку IndexError .
А тепер обговоримо нюанси індексації, які специфічні саме для Python.
Якщо ми працюємо зі змінними типами даних (ті ж списки), то індекси можуть бути використані не тільки для отримання значень, але і для присвоєння (заміни елементів об'єкта, що змінюється).
numbers = [1, 2, 8, 4] print(numbers) # [1, 2, 8, 4] # Змінюємо третій елемент списку numbers[2] = 3 print(numbers) # [1, 2, 3, 4]
Зворотня індексація у Python
Зворотна індексація Python передбачає доступ до елементів за допомогою негативних чисел. Вона починається з кінця об'єкта і йде у зворотному порядку. Тобто ми можемо отримати останній елемент за допомогою індексу -1. Доступ до передостаннього елементу можна отримати за допомогою -2 тощо.
Використання негативних індексів може бути корисним під час роботи зі списками варіативної довжини. Так зручно отримати доступ до елементів з кінця списку, не знаючи заздалегідь довжину списку.
Давайте візьмемо останній символ із рядка Zen of Python, використовуючи пряму та зворотну індексацію:
saying = "Simple is better than complex" # отримуємо останній елемент прямою індексацією print(saying[len(saying) - 1]) # x # використовуємо зворотну print(saying[-1]) # x
Робота з індексами в циклі for
Як ми згадували вище, в загальному випадку індекси не використовуються в циклах Python, хоча в деяких мовах без індексів не реалізувати ітерацію по елементах складеного об'єкта.Ось, наприклад, як це може виглядати на C:
#include int main(void) < const int LEN = 3; char chars[LEN] = ; , i, chars[i]); >> Знайдений символ за індексом 0: A Знайдено символ за індексом 1: B Знайдено символ за індексом 2: C
У Python, звичайно, можна виконувати ітерації за списком набагато простіше:
chars = ["A", "B", "C"] для char_ in chars: print(char_) # A # B # C
Так завжди і потрібно писати за винятком рідкісних ситуацій, коли нам потрібно безпосередньо оперувати з індексами в рамках логіки якогось алгоритму. Тут допоможе функція enumerate, яка дозволяє отримати і індекс, і значення одночасно. та в коді C:
chars = ["A", "B", "C"] для index, char in enumerate(chars): print(f"Знайдено символ за індексом : ") # Знайдено символ за індексом 0: A # Знайдено символ за індексом 1 : B # Знайдено символ за індексом 2: C
Зрізи Python: індекси на стероїдах
Зрізи — головне, що відрізняє функціонал індексів у Python від багатьох інших мов. дужки та має наступний базовий синтаксис:
- Значення start - це ціле число, яке є початком (лівою межею) зрізу. Якщо його не ставити, то за умовчанням дорівнює нулю, тобто початку послідовності.
- Значення stop — це ціле число, що є кінцем зрізу (його правий кордон) Дуже важливо пам'ятати, що правий кордон передбачає потрібний вам останній індекс. + 1. Тобто права межа сама по собі в результат не входить.
- Значення step – ціле число, крок зрізу, за умовчанням дорівнює 1.Крок зрізу послідовно додається до кожного індексу від лівої межі до правої, результуючі елементи будуть у вибірці. Тобто. якщо крок дорівнює 1, то береться кожен елемент, якщо 2 через один. А якщо крок дорівнює -1, то елементи вибираються праворуч наліво.
Давайте подивимося на це наочно, почавши зі зрізів із прямою індексацією:
numbers = [1, 2, 3, 4, 5] # зрізи від нуля до двох, з явним або неявним початком зрізу print("Індекси від нуля до двох") print(numbers[0:3]) print(numbers[: 3]) # варіант аналогічний попередньому # Індекси від нуля до двох # [1, 2, 3] [1, 2, 3] # Індекси від 3 до кінця списку print("\nІндекси від 3 до кінця списку") print(numbers[3:len(numbers)]) print(numbers[3:]) # Індекси від 3 до кінця списку # [4, 5] # [4, 5] # Робимо неглибоку копію списку print("\nКопія списку") print(numbers[:]) # Копія списку # [1, 2, 3, 4, 5] # Отримаємо всі елементи через 1 print("\nЗ кроком 2:") print(numbers[::2]) # З кроком 2: # [1, 3, 5]
Зрізи можуть бути зручними, наприклад, для видалення фіксованого префікса з рядків:
# Видаляємо "id-" з рядків у списку: order_items = ["id-999", "id-19098", "id-2"] cleaned = [item[3:] for item in order_items] print(cleaned) # ['999', '19098', '2']
У зрізах, звичайно, можна використовувати зворотну індексацію. Якщо задати крок -1, то отримаємо елементи у зворотному порядку.
numbers = [1, 2, 3, 4, 5] print(numbers[::-1]) print(numbers[4:2:-1]) # [5, 4, 3, 2, 1] # [5 , 4]
Негативний крок у зрізах у реальній практиці використовується нечасто, але на співбесідах ви можете натрапити на питання про те, як розгорнути рядок. Це можна зробити і за допомогою циклу, але не такої відповіді в ідеалі від вас чекають:)
Зрізи для присвоєння
Присвоєння зрізу замінює частину складового об'єкта вмістом іншого складового об'єкта. Кількість елементів, що додаються, не обов'язково має відповідати кількості елементів у зрізі, т.к.список без проблем збільшитися або зменшитися, якщо їх буде більше чи менше.
count_to_ten = [num for num in range(1, 11)] # Список з числами від 1 до 10 count_to_ten[3:6] = [20, 30] count_to_ten count_to_ten[6:8] = [100, 200, 300, 400 ] print(count_to_ten) # [1, 2, 3, 20, 30, 7, 100, 200, 300, 400, 10]
Нагадуємо, що для рядків та інших незмінних типів даних привласнення за індексом/зрізом не працюватиме.
Завдання з індексації та зрізів
Розв'яжіть кілька невеликих завдань самостійно для закріплення матеріалу:
1. Що ми отримаємо в результаті запуску наведеного нижче коду? Чи зможете ви замінити всі рядки, крім імпорту, на один print , який виведе аналогічний рядок?
з string import ascii_uppercase subset = "" для idx, letter in enumerate(ascii_uppercase): if idx % 4 == 0: subset = subset + letter print(subset)
2. Використовуючи ascii_uppercase, виведіть алфавіт у зворотному порядку за допомогою зрізу.
3. Знаходимо голку у стозі сіна. За допомогою зрізів, методу index та функції len виведіть рядок "голка", де б вона не розташовувалася в example .
example = "сіно сіно сіно голка сіно сіно сіно, привіт, привіт, поки."
4. За допомогою зрізу з наведеного нижче списку виведіть такий результат: [9, 6, 3]
count_to_ten = [num for num in range(1,11)] print(count_to_ten)
5. З наявного списку за допомогою індексів виведіть на екран лише слово "полуниця".
tokens = "Тут хоч десь можна купити полуницю?".split(" ") print(tokens)
6. Як ви вважаєте, що ми побачимо в результаті виклику claim.index("Python") ?
claim = "У тому матеріали ви дізналися про індекси та зрізи в Python".split() print(claim)
7. Що побачимо на екрані як висновок?
greeting = "Hello" print(greeting[4]) print(greeting[5])
Побутові оператори
Мова Python підтримує роботу з двійковими розрядами (бітами) цілих величин, де кожен біт числа розглядається окремо.Для забезпечення цього Python використовуються так звані бітові або порозрядні оператори, які реалізують загальновідомі бітові операції. Підтримка бітових операторів є також іншими мовами програмування.
У бітових операторах (операціях) кожен операнд сприймається як послідовність двійкових розрядів (біт), які набувають значення 0 чи 1 (двійкова система обчислення). Над цими розрядами можна виконувати відомі операції (логічне «І», логічне «АБО» тощо)
Перелік бітових операторів мови Python у порядку зменшення пріоритету наступний:
- ~ - бітовий оператор НІ (інверсія, найвищий пріоритет);
- , >> - Оператори зсуву вліво або зсуву вправо на задану кількість біт;
- & - бітовий оператор І (AND);
- ^ - бітове що виключає АБО (XOR);
- | - бітовий оператор АБО (OR).
2. Бітовий оператор ~ (інверсія). приклад
У бітовому операторі (операції) ~ інверсія значення будь-якого біта числа змінюється протилежне. Значення біта 0 встановлюється 1, а значення 1 встановлюється 0. Тобто, позитивне число стає негативним зі зміщенням -1. Також негативне число стає позитивним зі зміщенням на -1.
приклад.
# Бітовий оператор ~ НІ - інверсія a = 0b1001 # a = 9 у десятковій системі b = ~a # b = -10 – десяткова система c = bin(b) # c = -0b1010 – двійкова система a = -0b1001 # a = -9 у десятковій системі b = ~a # b = 8 - десяткова система c = bin(b) # c = 0b1000 – двійкова система a = 0b1111 # a = 15 b = ~a # b = -16 c = bin(b) # c = -0b10000 a = -0b1111 # a = -15 b = ~a # b = 14 c = bin(b) # c = 0b1110
3. Оператори зсуву вліво > . приклад
Оператори зсуву вліво та зсуву вправо >> зсувають кожен біт одну чи кілька позицій вліво чи вправо. Загальна форма операторів
де op1 , op2 - Операнди.Операндом може бути число, змінна цілісного типу або вираз, що повертає цілий результат.
На малюнку 1 продемонстровано роботу операторів зсуву вліво та зсуву вправо >> . При обчисленні значення y , значення x зсувається на 1 позицію вліво (випадок а) або праворуч (випадок b). Відповідно, результат y множиться на 2 або розділиться на 2.
Рисунок 1. Робота операцій: а) зсуву вліво (множення на 2); b) зрушення праворуч >> (цілочисленний поділ на 2)
Якщо потрібно помножити число на 16, потрібно зрушити це число на 4 біти вліво. Якщо потрібно розділити число на 8, потрібно зрушити це число на 3 біта вправо. Швидкість виконання операцій зсуву вище порівняно з операціями множення та поділу на числа кратні 2 у ступені N ( N - Кількість зрушених біт).
приклад.
# Операції зсуву вліво > x = 5 # Зрушення вліво на 3 знаки, множення на 2 3 = 8 y = x # y = x*2**3 = 40 print('x = ', x) print('y = x, y) x = 25 y = x >> 2 # y = 6
print('x = ', x) print('y = x>>2 = ', y) # Для негативних чисел x = -10 y = x # y = -20
print('x = ', x) print('y = x, y) x = -100 y = x >> 3 # y = -13
print('x = ', x) print('y = x>>3 = ', y)
Результат роботи програми
x = 5
y = x x = 25
y = x>>2 = 6
x = -10
y = x x = -100
y = x>>3 = -13
4. Бітовий оператор & (І, AND). приклад
Бітовий оператор І (AND) є бінарним і виконує побітове «І» для кожної пари бітів операндів, які розміщуються ліворуч та праворуч від знака оператора & . Загальна форма оператора
де op1 , op2 - Операнди. Операндами можуть бути числа, змінні цілісного типу або вирази, які повертають цілий результат.
Кожен цілий операнд розглядається як набір біт, над будь-яким з яких виконується побітова операція «І».
На малюнку 2 показано роботу бітової операції «І».
Малюнок 2.Бітовий оператор & «І»
Як видно з малюнка, біт в позиції 0 першого операнда (x) обчислюється з бітом у позиції 0 другого операнда (y), відповідно біт в позиції 1 першого операнда (x) обчислюється з бітом у позиції 1 другого операнда (y) і т.д. буд. При таких обчисленнях результуюче значення будь-якого біта визначається за такими формулами:
0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1
приклад.
# Бітова операція & (І, AND) x = 37 y = 58 z = x & y # z = 32
print('x = ', x) print('y = ', y) print('z = ', z)
Результат роботи програми
5. Битовий оператор ^ (що виключає АБО, XOR). приклад
Битовий оператор виняткове АБО позначається символом ^ і виконує операцію додавання по модулю 2 для будь-якого біта операндів. Загальна форма оператора
де op1 , op2 - Цілочисленні операнди.
Оператор виключає АБО (XOR) оперує двійковими розрядами. Кожен операнд сприймається як послідовність біт. Результат побитового виключає АБО визначається за такими формулами
0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0
На малюнку 3 відображено приклад бітового виключає АБО для двох операндів.
Малюнок 3. Битовий оператор «що виключає АБО»
приклад.
# Бітовий оператор - що виключає АБО (XOR) x = 37 y = 58 z = x ^ y # z = 31
print('x = ', x) print('y = ', y) print('z = ', z)
Результат роботи програми
6. Бітовий оператор | АБО (OR). приклад
Бітовий оператор АБО (OR) є бінарним і позначається символом | . Оператор реалізує побітове логічне додавання на зразок операторів & і ^ (Див. п.п. 4, 5).
Загальна форма бітового оператора | наступна
де op1 , op2 – операнди, які можуть бути змінними чи числами цілого типу.
Для двох операндів op1 , op2 бітове АБО виконується відповідно до таких правил
0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1
На малюнку 4 продемонстровано роботу бітового оператора АБО на прикладі двох довільних операндів
Малюнок 4. Битовий оператор АБО
приклад.
# Бітове АБО (OR) x = 37 y = 58 z = x | y # z = 63
print('x = ', x) print('y = ', y) print('z = ', z)
Результат роботи програми
7. Приклади використання бітових операторів
приклад 1. Витягнути з числа 4,5,6 біти та визначити їх ціле чисельне значення.
# Витягнути 4,5,6 біти цілого числа
# ввести ціле число number = int(input('Input number: ')) # Фільтр на 4,5,6 біти number &= 0b1110000 # зрушити на 4 розряди праворуч number >>= 4 print('number = ', Номер)
Результат роботи програми
Input number: 95
number = 5
приклад 2. Помножити значення двох чисел. У першому числі взяти біти, які розміщені у позиціях 0-5. У другому числі взяти біти, які розміщені у позиціях 0-7.
# Помножити 0-5 біти першого числа на 0-7 біти другого числа
# ввести цілі числа x = int(input('x = ')) y = int(input('y = ')) # Фільтр на 0-5 біти x &= 0b11111 # Фільтр на 0-7 біти y &= 0b1111111 # помножити z = x * y print('x = ', x) print('y = ', y) print('z = ', z)
Результат роботи програми
x = 234234253
y = 322797987
x = 13
y = 35
z = 455
Пов'язані теми