Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created April 20, 2026 09:24
Show Gist options
  • Select an option

  • Save sunmeat/ab181793d9e22277e5c5e70915a456ea to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/ab181793d9e22277e5c5e70915a456ea to your computer and use it in GitHub Desktop.
python questions

Python

Послідовності

Що таке послідовність

Послідовністю в Python називається ітерований об'єкт, який підтримує ефективний доступ до елементів за допомогою цілочисельних індексів через спеціальний метод __getitem__() та підтримує метод __len__(), що повертає довжину послідовності. До основних вбудованих типів послідовностей належать list, tuple, range, str та bytes.

Послідовності також опціонально можуть реалізовувати методи count(), index(), __contains__() та __reversed__() та інші.

Які операції підтримує більшість послідовностей

  • x in s, x not in s – чи знаходиться елемент x у послідовності s (для рядків та послідовностей байтів – чи є x підрядком s)
  • s + t – конкатенація послідовностей s та t
  • s * n, n * s – конкатенація n нерекурсивних копій послідовності s
  • s[i] – i-й елемент послідовності s
  • s[:i] - зріз усіх елементів послідовності s до i (не включаючи i)
  • s[i:] - зріз усіх елементів послідовності s від i до останнього елемента
  • s[-i:] - зріз останніх i елементів послідовності s
  • s[::-1] - перевернути послідовність
  • s[i:j] – зріз послідовності s від i до j (не включаючи j)
  • s[i:j:k] – зріз послідовності s від i до j з кроком k (не включаючи j)
  • len(s) – довжина послідовності s
  • min(s) – мінімальний елемент послідовності s
  • max(s) – максимальний елемент послідовності s
  • s.index(x[, i[, j]]) – індекс першого входження x (опціонально – починаючи з позиції i та до позиції j)
  • s.count(x) – загальна кількість входжень x у s
  • sum(s) – сума елементів послідовності

Незмінні послідовності зазвичай реалізують операцію hash(s) – хеш-значення об'єкта.

Більшість змінних послідовностей підтримують такі операції:

  • s[i] = x – елемент з індексом i замінюється на x
  • s[i:j] = t, s[i:j:k] = t – елементи з індексами від i до j (з кроком k) замінюються вмістом ітерованого об'єкта t
  • del s[i:j], del s[i:j:k] – видалення відповідних елементів з послідовності
  • s.append(x) – додавання x в кінець послідовності
  • s.clear() – видалення всіх елементів послідовності
  • s.copy() – нерекурсивна копія послідовності
  • s.extend(t) – додавання всіх елементів ітерованого об'єкта в кінець послідовності
  • s.insert(i, x) – вставка елемента x за індексом i
  • s.pop(), s.pop(i) – повернення значення за індексом i (за замовчуванням – останній елемент) та видалення його з послідовності
  • s.remove(x) – видалення першого входження x
  • s.reverse() – розворот послідовності у зворотньому порядку

Які види рядків бувають у Python

Залежить від версії Python. У другій гілці два типи: однобайтні рядки та Юнікод представлені класами str та unicode відповідно. У третьому Python є один вид рядків str, який представляє собою Юнікод. Однобайтних рядків немає, замість них є тип bytes, тобто ланцюжок байтів.

Чи можна змінити окремий символ всередині рядка

Ні, рядки незмінні. Операції заміни, форматування та конкатенації повертають новий рядок.

Як об'єднати список рядків в один. Як розбити рядок на список рядків

Щоб об'єднати, потрібен метод рядка .join(). Щоб розбити, метод .split().

Як кодувати та декодувати рядки

Кодувати – перевести Юнікод у байтовий рядок. Викликати метод .encode() у рядка.

Декодувати – відновити рядок із ланцюжка байтів. Викликати метод .decode() у об'єкта str або bytes (версії Python 2 та 3 відповідно).

В обох випадках явно передавати кодування, інакше буде використана та, що визначена в системі за замовчуванням. Бути готовим зловити виключення UnicodeEncodeError, UnicodeDecodeError.

Чим список відрізняється від кортежу

Списки – це змінні послідовності, які зазвичай використовуються для зберігання однотипних даних (хоча Python не забороняє зберігати в них дані різних типів). Представлені класом list.

Кортежі – це незмінні послідовності, які зазвичай використовуються для зберігання різнотипних даних. Представлені класом tuple.

На рівні мови відрізняються тим, що в кортеж не можна додати або прибрати елемент. На рівні інтерпретатора різниць немає. Обидві колекції представлені масивом вказівників на структуру PyObject.

Існують спеціальні функції для роботи зі списками. Вони викликаються методами списку. Нижче наведені найчастіше використовувані.

# Створюємо вихідний список
lst = [1, 2, 3]

# append(x): додає елемент у кінець списку
lst.append(4)
# Тепер lst = [1, 2, 3, 4]

# extend(iterable): розширює список, додаючи елементи з ітерованого об'єкта
lst.extend([5, 6])
# Тепер lst = [1, 2, 3, 4, 5, 6]

# insert(i, x): вставляє елемент x на позицію i
lst.insert(0, 'start')
# Тепер lst = ['start', 1, 2, 3, 4, 5, 6]

# remove(x): видаляє перше входження елемента x
lst.remove(3)
# Тепер lst = ['start', 1, 2, 4, 5, 6]

# pop([i]): видаляє та повертає елемент на позиції i (за замовчуванням останній)
last = lst.pop()
# last = 6, а lst = ['start', 1, 2, 4, 5]

# sort(): сортує список на місці
lst = [3, 1, 4, 1, 5, 9, 2]
lst.sort()
# Тепер lst = [1, 1, 2, 3, 4, 5, 9]

# reverse(): розвертає список на місці
lst.reverse()
# Тепер lst = [9, 5, 4, 3, 2, 1, 1]

Що таке діапазон

Діапазони – незмінні послідовності чисел, які задаються початком, кінцем та кроком. Представлені класом range (у Python 2 – xrange; range у Python 2 – це функція, яка повертає список). Параметри конструктора мають бути цілими числами (або екземпляри класу int, або будь-який об'єкт з методом __index__). Підтримує всі загальні для послідовностей операції, крім конкатенації та повторення, а також, у версіях Python до 3.2, зрізів та від'ємних індексів.

Як зробити список унікальним (без елементів, що повторюються)

Варіант з множиною. Не гарантує порядок елементів. Порядок зберігається тільки для маленьких списків.

list(set([1, 2, 2, 2, 3, 3, 1]))
>>> [1, 2, 3]

Варіант з OrderedDict. Гарантує порядок елементів.

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys([1, 2, 2, 2, 3, 3, 1]))
[1, 2, 3]

Варіант з циклом. Повільно, але гарантує порядок. Підходить, якщо елементи не можна поміщати всередину множини (наприклад, словники).

res = []
for x in [1, 2, 2, 2, 3, 3, 1]:
    if x not in res:
        res.append(x)
>>> [1, 2, 3]

Є кортеж з трьох елементів. Призначити змінним a, b, c його значення

a, b, c = (1, 2, 3)

Як порівнюються послідовності

Дві послідовності рівні, якщо вони мають однаковий тип, рівну довжину та відповідні елементи обох послідовностей рівні.

Послідовності однакових типів можна порівнювати. Порівняння відбуваються у лексикографічному порядку: послідовність меншої довжини менша, ніж послідовність більшої довжини, якщо ж їхні довжини рівні, то результат порівняння дорівнює результату порівняння перших елементів, що відрізняються.

Множини та відображення

Як зрозуміти, чи є об'єкт хешованим

Об'єкт називається хешованим, якщо він має хеш-значення (ціле число), яке ніколи не змінюється протягом його життєвого циклу та повертається методом __hash__(), та може порівнюватися з іншими об'єктами (реалізує метод __eq__()). Рівні хешовані об'єкти повинні мати рівні хеш-значення. Всі стандартні незмінні об'єкти хешовані. Всі стандартні змінні об'єкти не хешовані.

Що таке множина

Множина – це невпорядкована колекція хешованих об'єктів, які не повторюються. У множинах немає поняття позиції елемента. Відповідно, вони не підтримують індексацію та зрізи. Вбудовані класи множин: set (змінна множина), frozenset (незмінна множина).

Для чого застосовуються множини

Зазвичай використовуються для перевірки елемента на входження в множину та видалення повторень елементів і виконання таких операцій, як об'єднання, перетин, різниця та симетрична різниця.

Які операції можна виконувати над множинами

  • set([iterable]), frozenset([iterable]) – створення множини (порожньої або з елементів ітерованого об'єкта)
  • len(s) – кількість елементів множини
  • x in s, x not in s – перевірка наявності елемента в множині
  • s.isdisjoint(t) – перевірка того, що дана множина не має спільних елементів із заданою
  • s.issubset(t), s <= t – перевірка того, що всі елементи множини s є елементами множини t
  • s < t – перевірка того, що s <= t та s != t
  • s.isuperset(t), s >= t – перевірка того, що всі елементи множини t є елементами множини s
  • s > t – перевірка того, що s >= t та s != t
  • s.union(t, ...), s | t | ... – створення нової множини, яка є об'єднанням даних множин
  • s.intersection(t, ...), s & t & ... – створення нової множини, яка є перетином даних множин
  • s.difference(t, ...), s - t - ... – створення нової множини, яка є різницею даних множин
  • s.symmetric_difference(t), s ^ t – створення нової множини, яка є симетричною різницею даних множин (тобто різниця об'єднання та перетину множин)
  • s.copy() – неповна копія множини s

Операції над множинами, які є методами, приймають як аргументи будь-які ітеровані об'єкти. Операції над множинами, записані у вигляді бінарних операцій, вимагають, щоб другий операнд операції теж був множиною, та повертають множину того типу, яким була перша множина.

Операції над змінними множинами:

  • s.update(t, ...), s |= t | ... – додати до даної множини елементи з інших множин
  • s.intersection_update(t, ...), s &= t & ... – залишити в даній множині тільки ті елементи, які є й в інших множинах
  • s.difference_update(t, ...), s -= t | ... – видалити з даної множини ті елементи, які є в інших множинах
  • s.symmetric_difference_update(t), s ^= t – залишити або додати в s елементи, які є або в s, або в t, але не в обох множинах
  • s.add(element) – додати новий елемент до множини
  • s.remove(element) – видалити елемент з множини; якщо такого елемента немає, виникає виключення KeyError
  • s.discard(element) – видалити елемент з множини, якщо він у ній знаходиться
  • s.pop() – видалити з множини та повернути довільний елемент; якщо множина порожня, виникає виключення KeyError
  • s.clear() – видалити всі елементи множини

Як відбувається перевірка множин на рівність

Перевірка множин на рівність відбувається поелементно, незалежно від типів множин.

Що таке відображення

Відображення (mapping) – це об'єкт-контейнер, який підтримує довільний доступ до елементів за ключами та описує всі методи, описані в абстрактному базовому класі collections.Mapping (get(), items(), keys(), values()) або collections.MutableMapping (clear(), get(), items(), keys(), pop(), popitem(), setdefault(), update(), values()). До відображень належать класи dict, collections.defaultdict, collections.OrderedDict та collections.Counter.

Які нюанси є у використанні чисел як ключів

Числові ключі в словниках підпорядковуються правилам порівняння чисел. Таким чином, int(1) та float(1.0) вважаються однаковим ключем. Однак через те, що значення типу float зберігаються наближено, не рекомендується використовувати їх як ключі.

>>> {True: 'yes', 1: 'no', 1.0: 'maybe'}
{True: 'maybe'}

Які операції можна виконувати над відображеннями

  • len(d) – кількість елементів.
  • d[key] – отримання значення з ключем key. Якщо такий ключ не існує і відображення реалізує спеціальний метод __missing__(self, key), то він викликається. Якщо ключ не існує і метод __missing__ не визначений, кидається виключення KeyError.
  • d[key] = value – змінити значення або створити нову пару ключ-значення, якщо ключ не існує.
  • key in d, key not in d – перевірка наявності ключа у відображенні.
  • iter(d) – те саме, що iter(d.keys()).
  • clear() – видалити всі елементи словника.
  • copy() – створити неповну копію словника.
  • (метод класу) dict.fromkeys(sequence[, value]) – створює новий словник з ключами з послідовності sequence та заданим значенням (за замовчуванням – None).
  • d.get(key[, default]) – безпечне отримання значення за ключем (ніколи не кидає KeyError). Якщо ключ не знайдено, повертається значення default (за замовчуванням – None).
  • d.items() – у Python 3 повертає об'єкт представлення словника, що відповідає парам (двоелементним кортежам) виду (ключ, значення). У Python 2 повертає відповідний список, а метод iteritems() повертає ітератор.
  • d.keys() – у Python 3 повертає об'єкт представлення словника, що відповідає ключам словника. У Python 2 повертає відповідний список, а метод iterkeys() повертає ітератор.
  • d.pop(key[, default]) – якщо ключ key існує, видаляє елемент зі словника та повертає його значення. Якщо ключ не існує і задано значення default, повертається це значення, інакше кидається виключення KeyError.
  • d.popitem() – видаляє довільну пару ключ-значення та повертає її. Якщо словник порожній, виникає виключення KeyError.
  • d.setdefault(key[, default]) – якщо ключ key існує, повертає відповідне значення. Інакше створює елемент з ключем key та значенням default. default за замовчуванням дорівнює None.
  • d.update(mapping) – приймає або інший словник або відображення, або ітерований об'єкт, що складається з ітерованих об'єктів – пар ключ-значення, або іменовані аргументи. Додає відповідні елементи до словника, перезаписуючи елементи з існуючими ключами.
  • d.values() – у Python 3 повертає об'єкт представлення словника, що відповідає значенням. У Python 2 повертає відповідний список, а метод itervalues() повертає ітератор.

Що повертає метод items

Об'єкти, що повертаються методами items(), keys() та values() – це об'єкти представлення словника. Вони надають динамічне представлення елементів словника, тобто зміни даного словника автоматично відображаються і на цих об'єктах.

Операції з представленнями словників:

  • iter(dictview) – отримання ітератора за ключами, значеннями або парами ключів та значень.
  • len(dictview) – кількість елементів у словнику.
  • x in dictview – перевірка існування ключа, значення або пари ключ-значення в словнику.

Як відсортувати список словників за певним полем

Метод списку .sort() і вбудована функція sorted() приймають параметр key. Ним має бути викликуваний об'єкт, який приймає черговий елемент (у нашому випадку словник) і повертає значення-критерій сортування.

Код нижче показує, як відсортувати список людей за віком:

users = [{'age': 30}, {'age': 20}, {'age': 10}]
users.sort(key=lambda user: user['age'])
>>> [{'age': 10}, {'age': 20}, {'age': 30}]

Що може бути ключем словника. Що не може. Чому

Ключем словника може бути будь-який хешований незмінний об'єкт: число, рядок, datetime, функція і навіть модуль. Такі об'єкти мають метод __hash__(), який однозначно зіставляє об'єкт з деяким числом. За цим числом словник шукає значення для ключа.

Списки, словники та множини змінні та не мають методу хешування. При підстановці їх у словник виникне помилка.

Хеш кортежу обчислюється рекурсивно за всіма елементами. Так, кортеж (1, (True, (42, ('hello', )))) складається тільки з незмінних елементів, тому може бути ключем. Однак такий кортеж (1, (True, (42, ({'hello': 'world'}, )))) містить глибоко всередині словник, тому хеш не може бути розрахований.

Є два списки – ключі та значення. Як скласти з них словник

keys = ['foo', 'bar', 'baz']
vals = [1, 2, 3]
dict(zip(keys, vals))
>>> {'baz': 3, 'foo': 1, 'bar': 2}

Функція zip віддає список пар N-х елементів. Конструктор dict приймає список пар. Кожну пару він розглядає як ключ та значення відповідно.

Як працює хеш-таблиця

Хеш-таблиця – це розріджений масив (масив, у якому є незаповнені позиції). Ячейки хеш-таблиці в dict містять два поля: посилання на ключ і посилання на значення елемента.

Python прагне залишати не менше третини ячейок порожніми; якщо хеш-таблиця стає надмірно заповненою, вона копіюється в нову ділянку пам'яті, де є місце для більшої кількості ячейок.

Для поміщення елемента в хеш-таблицю потрібно насамперед обчислити хеш-значення ключа елемента. Це робить вбудована функція hash().

Що таке колізія

Коли хеш-функція повертає однакову відповідь для різних даних.

Де буде швидший пошук, а де перебір і чому: dict, list, set, tuple

Пошук буде швидшим у dict та set, тому що це хеш-таблиці, доступ до елемента яких виконується за O(1). Для list та tuple пошук буде виконуватися в середньому за O(n).

Виняток працює тільки для дуже маленьких списків довжиною до 5 елементів. У цьому випадку інтерпретатору буде швидше пробігтися по списку, ніж обчислити хеш.

Функції

Що таке args, kwargs. У яких випадках вони потрібні

Вирази *args та **kwargs оголошують у сигнатурі функції. Вони означають, що всередині функції будуть доступні змінні з іменами args та kwargs (без зірочок).

args – це кортеж, який накопичує позиційні аргументи. kwargs – словник іменованих аргументів, де ключ – ім'я параметра, значення – значення параметра.

Важливо: якщо у функцію не передано жодних параметрів, змінні будуть відповідно рівні порожньому кортежу та порожньому словнику, а не None.

Чому використовувати змінні об'єкти як параметри за замовчуванням погано. Наведіть приклад поганого випадку. Як виправити

Функція створюється одного разу при завантаженні модуля. Іменовані параметри та їх дефолтні значення теж створюються один раз та зберігаються в одному з полів об'єкта-функції.

У нашому прикладі bar дорівнює порожньому списку. Список – змінна колекція, тому значення bar може змінюватися від виклику до виклику. Приклад:

def foo(bar=[]):
    bar.append(1)
    return bar
foo()
>>> [1]
foo()
[1, 1]
foo()
>>> [1, 1, 1]

Хорошим тоном вважається вказувати параметру порожнє незмінне значення, наприклад 0, None, '', False. У тілі функції перевіряти на заповненість та створювати нову колекцію:

def foo(bar=None):
    if bar is None:
        bar = []
    bar.append(1)
    return bar
foo()
>>> [1]
foo()
>>> [1]
foo()
>>> [1]

Сказане вище актуально в т.ч. для множин та словників.

Чи можна передавати функцію як аргумент іншої функції

Можна, функція у Python є об'єктом першого порядку: допускає присвоєння, передачу у функцію, видалення.

Чи можна оголошувати функцію всередині іншої функції. Де вона буде видима

Можна. Така функція буде видима тільки всередині першої функції.

Що таке лямбди. Які їх особливості

Це анонімні функції. Вони не резервують імені в просторі імен. Лямбди часто передають у функції map, reduce, filter.

Лямбди у Python можуть складатися тільки з одного виразу. Використовуючи синтаксис дужок, можна оформити тіло лямбди у кілька рядків.

Використовувати крапку з комою для розділення операторів не можна.

Чи допустимі такі вирази

  • nope = lambda: pass
  • riser = lambda x: raise Exception(x)

Ні, при завантаженні модуля виникне виключення SyntaxError. У тілі лямбди може бути тільки вираз. pass та raise є операторами.

Як передаються значення аргументів у функцію або метод

У таких мовах, як C++, є змінні, що зберігаються на стеку та у динамічній пам'яті. При виклику функції ми поміщаємо всі аргументи на стек, після чого передаємо управління функції.

У Python відмовились від такого механізму, замінювачем служить механізм зв'язування (assignment) імені змінної з об'єктом, наприклад при створенні змінної: var = "john"

Інтерпретатор створює об'єкт «john» і «ім'я» var, а потім зв'язує об'єкт з даним ім'ям. При виклику функції нових об'єктів не створюється, замість цього у її просторі видимості створюється ім'я, яке зв'язується з існуючим об'єктом.

Що таке замикання

Синтаксично це виглядає як функція, що знаходиться повністю в тілі іншої функції. При цьому вкладена внутрішня функція містить посилання на локальні змінні зовнішньої функції. Кожного разу при виконанні зовнішньої функції відбувається створення нового екземпляра внутрішньої функції, з новими посиланнями на змінні зовнішньої.

Ітератори та генератори

Що таке контейнер

Контейнер – це тип даних, який інкапсулює в собі значення інших типів. Списки, кортежі, множини, словники тощо є контейнерами.

Що таке ітерований об'єкт

Ітерований об'єкт (в оригінальній термінології – «iterable») – це об'єкт, який може повертати значення по одному за раз. Приклади: всі контейнери та послідовності (списки, рядки тощо), файли, а також екземпляри будь-яких класів, у яких визначений метод __iter__() або __getitem__(). Ітеровані об'єкти можуть бути використані всередині циклу for, а також у багатьох інших випадках, коли очікується послідовність (функції sum(), zip(), map() тощо).

Що таке ітератор

Ітератор (iterator) – це об'єкт, який представляє потік даних. Повторюваний виклик методу __next__() (next() у Python 2) ітератора або передача його вбудованій функції next() повертає подальші елементи потоку.

Якщо більше не залишилось даних, кидається виключення StopIteration. Після цього ітератор вичерпаний і будь-які подальші виклики його методу __next__() знову генерують виключення StopIteration.

Ітератори зобов'язані мати метод __iter__, який повертає сам об'єкт ітератора, тому будь-який ітератор також є ітерованим об'єктом.

Що таке генератор

Залежно від контексту, може означати або функцію-генератор, або ітератор генератора (частіше всього останнє). Методи __iter__ та __next__ у генераторів створюються автоматично.

З точки зору реалізації, генератор у Python — це мовна конструкція, яку можна реалізувати двома способами: як функція з ключовим словом yield або як генераторний вираз.

Що таке генераторна функція

Генераторна функція – функція, у тілі якої зустрічається ключове слово yield. Будучи викликаною, така функція повертає об'єкт-генератор.

Що робить yield

yield заморожує стан функції-генератора та повертає поточне значення. Після наступного виклику __next__() функція-генератор продовжує своє виконання з того місця, де вона була призупинена.

У чому відмінність [x for x in y] від (x for x in y)

Перший вираз повертає список (спискове включення), другий – генератор.

Що особливого у генераторі

Генератор зберігає в пам'яті не всі елементи, а тільки внутрішній стан для обчислення чергового елемента. На кожному кроці можна обчислити тільки наступний елемент, але не попередній. Пройти генератор у циклі можна тільки один раз.

Як оголосити генератор

  • використати синтаксис (x for x in seq)
  • оператор yield у тілі функції замість return
  • вбудована функція iter, яка викликає у об'єкта метод __iter__(). Цей метод має повертати генератор.

Як отримати з генератора список

Передати його в конструктор списку: list(x for x in some_seq). Важливо, що після цього по генератору вже не можна буде ітеруватися.

Що таке підгенератор

У Python 3 існують так звані підгенератори (subgenerators). Якщо у функції-генераторі зустрічається пара ключових слів yield from, після яких слідує об'єкт-генератор, то даний генератор делегує доступ до підгенератора, поки він не завершиться, після чого продовжує своє виконання.

Які методи є у генераторів

  • __next__() – починає або продовжує виконання функції-генератора.
  • send(value) – продовжує виконання та надсилає значення у функцію-генератор.
  • throw(type[, value[, traceback]]) – кидає виключення типу type в місці, де був призупинений генератор.
  • close() – кидає виключення GeneratorExit в місці, де був призупинений генератор.

Чи можна витягти елемент генератора за індексом

Ні, буде помилка. Генератор не підтримує метод __getitem__.

Що повертає ітерація по словнику

Ключ. Порядок ключів у Python 3.7+ гарантується (порядок вставки). Для ітерації по парах ключ-значення використовується метод .items().

Як ітерувати словник по парах ключ-значення

Метод словника .items() повертає генератор кортежів (key, value).

Що таке сопрограма

Сопрограма (англ. coroutine) — компонент програми, що узагальнює поняття підпрограми, який додатково підтримує безліч точок входу та зупинку і продовження виконання зі збереженням певного положення. Python 3.5 включає підтримку сопрограм на рівні мови. Для цього використовуються ключові слова async та await.

Класи, об'єкти

Як отримати список атрибутів об'єкта

Функція dir повертає список рядків – полів об'єкта. Поле __dict__ містить словник виду {поле -> значення}.

Що таке магічні методи, для чого потрібні

Магічними методами називають методи, імена яких починаються та закінчуються подвійним підкресленням. Магічні вони тому, що майже ніколи не викликаються явно. Їх викликають вбудовані функції або синтаксичні конструкції. Наприклад, функція len() викликає метод __len__() переданого об'єкта.

Деякі магічні методи:

  • __init__: ініціалізатор класу
  • __add__: додавання з іншим об'єктом
  • __eq__: перевірка на рівність з іншим об'єктом
  • __iter__: повертає ітератор

Як у класі послатися на батьківський клас

Функція super приймає клас та екземпляр:

class NextClass(FirstClass):
    def __init__(self, x):
        super(NextClass, self).__init__()
        self.x = x

Чи можливе множинне наслідування

Так, можна вказати більше одного батька в класі-нащадку.

Що таке MRO

MRO – method resolution order, порядок розв'язання методів. Алгоритм, за яким слід шукати метод у випадку, якщо у класу два і більше батьків.

При наслідуванні класів нового стилю застосовується правило MRO (порядок розв'язання методів), тобто лінеаризований обхід дерева класів. Такий алгоритм називається C3-лінеаризація.

Що таке Diamond problem

При ромбовидному наслідуванні визначити метод якого класу має бути викликаний.

Що таке міксини

Міксин (mix-in), патерн проектування в ООП, коли в ланцюжок наслідування додається невеликий клас-помічник. Наприклад:

class NowMixin(object):
    def now():
        return datetime.datetime.utcnow()

Тоді будь-який клас, успадкований з цим міксином, матиме метод now().

Що таке контекстний менеджер. Як написати свій

У Python є оператор with. Розміщений всередині код виконується з особливістю: до і після гарантовано спрацьовують події входу до блоку with та виходу з нього.

Події входу і виходу з блоку визначені методами __enter__ та __exit__. Перший спрацьовує в той момент, коли хід виконання програми переходить всередину with. __exit__ спрацьовує в момент виходу з блоку, в т.ч. і через виключення.

with open('file.txt') as f:
    data = f.read()
process_data(data)

Приклад реалізації власного контекстного менеджера на основі класу:

class Printable:
    def __enter__(self):
        print('enter')

    def __exit__(self, type, value, traceback):
        print('exit')

Приклад реалізації з використанням бібліотеки contextlib:

from contextlib import contextmanager

@contextmanager
def printable():
    print('enter')
    try:
      yield
    finally:
      print('exit')

Прокоментувати вираз

object() == object()

Завжди хибно, оскільки за замовчуванням об'єкти порівнюються за полем id (адреса в пам'яті), якщо тільки не перевизначений метод __eq__.

Що таке __slots__. Плюси, мінуси

Класи зберігають поля та їх значення у секретному словнику __dict__. Параметр __slots__ у класі жорстко фіксує набір полів класу. Слоти використовуються коли у класу може бути дуже багато полів, або коли критична продуктивність, або коли в процесі виконання програми створюються мільйони екземплярів класу.

Недолік: не можна присвоїти класу поле, якого немає в слотах. Не працюють методи __getattr__ та __setattr__.

У чому сенс параметрів _value, __value

Поле класу з одним лідируючим підкресленням говорить про те, що параметр використовується тільки всередині класу. При цьому він доступний для звернення ззовні. Це обмеження доступу тільки на рівні угоди.

Поля з подвійним підкресленням доступні всередині класу, але недоступні ззовні. Це досягається хитрим прийомом: інтерпретатор призначає таким полям імена вигляду _<ClassName>__<fieldName>. Описаний механізм називається name mangling.

class Foo(object):
    def __init__(self):
        self.__bar = 42

Foo().__bar
>>> AttributeError: 'Foo' object has no attribute '__bar'
Foo()._Foo__bar
>>> 42

Що таке __new__. І чим він відрізняється від __init__. У якій послідовності вони виконуються

Основна різниця між цими двома методами полягає в тому, що __new__ обробляє створення об'єкта, а __init__ обробляє його ініціалізацію.

__new__ викликається автоматично при виклику імені класу (при створенні екземпляра), тоді як __init__ викликається кожного разу, коли екземпляр класу повертається __new__.

Спочатку викликається __new__, а потім __init__.

Що таке і чим відрізняється old-style від new-style classes

Класи нового стилю (3.х доступні тільки вони, у 2.х при наслідуванні від object) відрізняються від класичних (за замовчуванням у 2.х) такими особливостями:

  • Ромбовидні шаблони множинного наслідування мають дещо інший порядок пошуку (MRO, C3-лінеаризація).
  • Класи тепер позначають типи, а типи є класами.
  • Всі класи наслідують від вбудованого класу object.

Що таке качина типізація

Неявна типізація, латентна типізація або качина типізація (англ. Duck typing) – вид динамічної типізації, коли межі використання об'єкта визначаються його поточним набором методів та властивостей, на противагу наслідуванню від певного класу. Тобто вважається, що об'єкт реалізує інтерфейс, якщо він містить всі методи цього інтерфейсу, незалежно від зв'язків в ієрархії наслідування.

Модулі, пакети

Що таке модуль

Модуль – функціонально закінчений фрагмент програми, оформлений у вигляді окремого файлу з вихідним кодом. Файл, який містить вихідний код на мові Python, є модулем.

Як можна отримати ім'я модуля

Назва модуля доступна в його глобальній змінній __name__. Якщо модуль не імпортований, а запущений як скрипт, то __name__ встановлюється у значення "__main__".

Як Python шукає модулі при імпорті

При імпортуванні модулів інтерпретатор Python шукає їх у директоріях та архівах, список яких доступний у змінній sys.path. За замовчуванням sys.path складається з директорії з запускуваним скриптом, вмісту змінної оточення PYTHONPATH та стандартного розташування модулів.

Що таке пакет

Модулі можуть об'єднуватися в пакети. Пакети служать як простори імен для модулів та спосіб їх структурування. Для того, щоб директорія була пакетом, у ній має знаходитися файл __init__.py.

Виключення

Що таке обробка виключень

Обробка виняткових ситуацій або обробка виключень (англ. exception handling) — механізм мов програмування, призначений для опису реакції програми на помилки часу виконання та інші можливі проблеми (виключення), які можуть виникнути при виконанні програми.

Код на Python може згенерувати виключення за допомогою ключового слова raise.

Для чого можуть застосовувати конструкцію try finally без except

try:
    # деякий код
finally:
    # деякий код

Якщо в блоці try відбудеться помилка, блок finally все одно буде виконаний і всередині нього можна буде зробити "cleanup", наприклад.

Як правильно по-різному обробляти виключення

Блоки except обробляються зверху вниз і управління передається не більш ніж одному обробнику. Тому при необхідності по-різному обробляти виключення, що знаходяться в ієрархії наслідування, спочатку потрібно вказувати обробники менш загальних виключень, а потім – більш загальних.

Що станеться, якщо помилку не обробить блок except

Якщо жоден з заданих блоків except не перехоплює виникле виключення, то воно буде перехоплено найближчим зовнішнім блоком try/except, у якому є відповідний обробник. Якщо ж програма не перехоплює виключення взагалі, то інтерпретатор завершує виконання програми та виводить інформацію про виключення в стандартний потік помилок sys.stderr.

Що робити, якщо потрібно перехопити виключення, виконати дії та знову збудити це саме виключення

Для того, щоб в обробнику виключення виконати певні дії, а потім передати виключення далі, використовується ключове слово raise без параметрів.

try:
    1 / 0
except ZeroDivisionError:
  # деяка логіка
  raise

Що таке ланцюжок виключень

У Python 3 при збудженні виключення в блоці except, старе виключення зберігається в атрибуті __context__. Також можна пов'язувати виключення в один ланцюжок: raise нове_виключення from старе_виключення або raise нове_виключення from None.

Навіщо потрібен блок else

Блок else виконується, якщо в процесі виконання блоку try не виникло виключень. Він призначений для того, щоб відокремити код, який може викликати виключення, від коду, який не повинен потрапляти під обробку в даному блоці.

Які є класи виключень

  • Базові:
    • BaseException – базовий клас для всіх виключень.
    • Exception – базовий клас для всіх стандартних виключень, що не вказують на обов'язкове завершення програми.
    • ArithmeticError – базовий клас для всіх виключень, пов'язаних з арифметичними операціями.
    • LookupError – базовий клас для виключень, пов'язаних з невірним ключем або індексом колекції.
  • Деякі з конкретних стандартних виключень:
    • AssertionError, AttributeError, ImportError, IndexError, KeyboardInterrupt, MemoryError, NameError, NotImplementedError, OSError, OverflowError, RuntimeError, SyntaxError, SystemError, SystemExit, TypeError, ValueError, ZeroDivisionError та інші.

Чи можна створювати власні виключення

Можна. Вони мають бути нащадками класу Exception. Прийнято називати виключення так, щоб ім'я їхнього класу закінчувалося словом Error.

Декоратори

Що таке декоратори. Навіщо потрібні

Декоратор у широкому сенсі – патерн проектування, коли один об'єкт змінює поведінку іншого. У Python декоратор, як правило, це функція A, яка приймає функцію B та повертає функцію C. При цьому функція C задіює в собі функцію B.

Задекорувати функцію означає замінити її на результат роботи декоратора.

Що може бути декоратором. До чого може бути застосований декоратор

Декоратором може бути будь-який викликуваний об'єкт: функція, лямбда, клас, екземпляр класу. У останньому випадку визначте метод __call__.

Застосовувати декоратор можна до будь-якого об'єкта. Найчастіше до функцій, методів та класів.

def auth_only(view):
    ...

@auth_only
def dashboard(request):
    ...

Що буде, якщо декоратор нічого не повертає

Якщо в тілі функції немає оператора return, виклик поверне None. У нашому випадку декоратор поверне None і функція, яку ми декоруємо, теж стане None. При спробі викликати її після декорування отримаємо помилку "NoneType is not callable".

У чому відмінність @foobar від @foobar()

Перше – звичайне декорування функцією foobar.

Другий випадок – декорування функцією, яку поверне виклик foobar. Інакше це називається параметричний декоратор або фабрика декораторів.

Що таке фабрика декораторів

Це функція, яка повертає декоратор. Наприклад:

from functools import wraps

def has_perm(perm):
    def decorator(view):
        @wraps(view)
        def wrapper(request):
            if perm in request.user.permissions:
                return view(request)
            else:
                return HTTPRedirect('/login')
        return wrapper
    return decorator

@has_perm('view_user')
def users(request):
    ...

Навіщо потрібен wraps

wraps – декоратор зі стандартної поставки Python, модуль functools. Він призначає функції-враперу ті самі поля __name__, __module__, __doc__, що і у вихідної функції, яку ви декоруєте.

Метакласи

Що таке метакласи

Метаклас – це «штука», яка створює класи.

Ми створюємо клас для того, щоб створювати об'єкти, так? А класи є об'єктами. Метаклас – це те, що створює ці самі об'єкти.

Що таке type. Як працює пошук метакласу при створенні об'єкта

type – це метаклас, який Python внутрішньо використовує для створення всіх класів.

Коли ви пишете:

class Foo(Bar):
  pass

Python робить наступне:

  • Чи є у класу Foo атрибут __metaclass__?
  • Якщо так, створює в пам'яті об'єкт-клас з іменем Foo, використовуючи те, що вказано в __metaclass__.
  • Якщо Python не знаходить __metaclass__, він шукає __metaclass__ у батьківському класі Bar.
  • Якщо ж __metaclass__ не знаходиться ніде, Python використовує type для створення об'єкта-класу.

Навіщо взагалі використовувати метакласи

Основне застосування метакласів – це створення API. Типовий приклад — Django ORM.

Введення-Виведення

Що таке файловий об'єкт

Файловий об'єкт – об'єкт, що надає файл-орієнтований API (методи read(), write() тощо) для доступу до ресурсу. Файлові об'єкти також називають потоками. Файлові об'єкти є контекстними менеджерами.

Які є види файлових об'єктів

У Python 3 існує три види файлових об'єктів: текстові файли (text files), «звичайні» (небуферизовані) бінарні файли та буферизовані бінарні файли.

У чому відмінність текстових та бінарних файлів

Текстові файли записують та зчитують дані типу str та автоматично виконують перетворення кодувань та кінців рядків. Бінарні файли записують та зчитують дані типів bytes та bytearray та не виконують жодних маніпуляцій з даними.

Як користуватися функцією open

Основні параметри:

  • file – ім'я файлу або файловий дескриптор;
  • mode – режим відкриття файлу;
  • encoding – кодування файлу;
  • buffering – чи використовувати буферизацію.

mode може починатися з символів «r» (читання), «w» (запис), «x» (ексклюзивне створення), «a» (додавання). Також параметр mode може мати другу букву для визначення типу файлу: «t» для текстового (за замовчуванням) та «b» для бінарного.

Для чого необхідно закривати файли

Після закінчення роботи з файлом слід обов'язково його закрити за допомогою методу close(), особливо якщо він був відкритий для запису. При використанні буферизованого виводу дані не потрапляють у файл одразу, а записуються в буфер.

Що таке серіалізація

Серіалізація – це процес збереження об'єктів у двійковому або рядковому вигляді для зберігання, передачі та відновлення. Зворотній процес називається десеріалізацією.

json.dumps / json.dump, json.loads / json.load

Функція dumps модуля json зберігає JSON-представлення об'єкта в рядок. Функція dump – у текстовий файл. Функція loads модуля json завантажує об'єкт із рядка. Функція load – з текстового файлу.

Тестування

Що таке mocking

Mock на англійській означає «імітація», «підробка». Якщо потрібно тестувати функцію, то всe, що не відноситься до неї самої (наприклад, читання з диска або з мережі), можна замінити макетами-пустишками.

Які ви знаєте види тестів

Unit-тести

Модульні тести перевіряють, чи правильно працює кожен окремий модуль (юніт) вашого коду. Модульні тести не повинні перевіряти зовнішні залежності або взаємодії.

Інтеграційні тести (Integration tests)

Інтеграційні тести перевіряють взаємодію між двома (або більше) окремими юнітами вашого коду. Також перевіряють інтеграцію вашого коду із зовнішніми залежностями.

Функціональне тестування

Функціональне тестування може бути визначене як тестування окремих функцій модулів. Воно значно відрізняється від модульного або інтеграційного тестування; цей тип тестування проводиться більше з точки зору користувача.

Системний тест (System test, Service test)

Автоматизовані тести, що перевіряють роботу всієї інтегрованої системи.

Регресійне тестування (Regression testing)

Це може бути будь-який вид тесту, який пишеться після того, як була виявлена проблема. Тест має емулювати точно кроки для відтворення проблеми.

Чим інтеграційне тестування відрізняється від функціонального

Інтеграційне тестування проводиться після модульного, а функціональне – метод тестування чорного ящика. Функціональне тестування також згадується як тестування E2E для тестування браузера.

Функціональне програмування

Що таке функціональне програмування

Функціональне програмування – розділ дискретної математики та парадигма програмування, в якій процес обчислення трактується як обчислення значень функцій у математичному розумінні.

Що таке об'єкт першого класу

Об'єктами першого класу (англ. first-class object) у контексті конкретної мови програмування називаються сутності, які можуть бути передані як параметр, повернуті з функції, присвоєні змінній. У Python функції є об'єктами першого класу.

Що таке функція вищого порядку

Функція вищого порядку – функція, що приймає як аргументи інші функції або повертає іншу функцію як результат.

Що таке каррінг

Каррінг — це перетворення функції від багатьох аргументів у набір функцій, кожна з яких є функцією від одного аргументу.

def greet_curried(greeting):
    def greet(name):
        print(greeting + ', ' + name)
    return greet

greet_hello = greet_curried('Hello')
greet_hello('German')
greet_hello('Ivan')

Опишіть функції map, reduce, filter модуля functools

Функція map застосовує функцію до кожного елемента послідовності. У Python 3 – повертає об'єкт-ітератор.

Функція filter залишає лише ті елементи послідовності, для яких задана функція істинна. У Python 3 – повертає об'єкт-ітератор.

Функція reduce (у Python 3 знаходиться в модулі functools) приймає функцію від двох аргументів, послідовність та опціональне початкове значення і обчислює згортку послідовності.

Які інші функції ви знаєте з модуля functools

  • lru_cache – декоратор, який кешує значення функцій;
  • partial – часткове застосування функції.

Які функції ви знаєте з модуля itertools

  • product – декартовий добуток ітераторів;
  • permutations – генерація перестановок;
  • combinations – генерація комбінацій;
  • chain – з'єднання кількох ітераторів в один;
  • takewhile – отримання значень послідовності, поки значення функції-предикату для її елементів істинне;
  • dropwhile – отримання значень послідовності починаючи з елемента, для якого значення функції-предикату перестане бути істинним.

GIL, потоки, процеси

Що таке GIL. Які у нього є проблеми

У будь-який момент може виконуватися тільки один потік Python. Глобальне блокування інтерпретатора — GIL — ретельно контролює виконання тредів. GIL гарантує кожному потоку ексклюзивний доступ до змінних інтерпретатора.

Проблема в тому, що через GIL далеко не всі завдання можуть бути вирішені в тредах. Навпаки, їх використання найчастіше знижує швидкодію програми (при CPU-bound задачах).

Чи працювали ви з asyncio. У чому його особливість

asyncio використовує сопрограми – вони виконують тільки корисну роботу, а перемикання між ними відбувається тільки в той момент, коли сопрограма очікує завершення якоїсь зовнішньої операції.

Потоки будуть простіше, якщо у вас типовий веб-додаток, який не залежить від зовнішніх сервісів. AsyncIO підійде, якщо додаток більшу частину часу витрачає на читання/запис даних.

Що таке async/await, для чого вони потрібні та як їх використовувати

Ключове слово async йде до def, щоб показати, що метод є асинхронним. Ключове слово await показує, що ви очікуєте завершення сопрограми.

import asyncio
import aiohttp

async def call_url(url):
    async with aiohttp.ClientSession() as session:
        print('Starting {}'.format(url))
        async with session.get(url) as response:
            data = await response.text()
            return data

Як у Python реалізується багатопотоковість. Якими модулями

Багатопотоковість досягається модулем Threading. Це нативні Posix-треди, які виконуються на рівні операційної системи.

У чому відмінність тредів від мультипроцесингу

Головна відмінність у розподілі пам'яті. Процеси незалежні один від одного, мають роздільні адресні простори. Треди виконуються у спільному адресному просторі, мають спільний доступ до пам'яті, змінних, завантажених модулів.

Що таке гринлети. Загальне поняття. Приклади реалізацій

Greenlet == Зелені треди == легковагові треди всередині віртуальної машини. Операційна система їх не бачить. Такими тредами управляє сама віртуальна машина. Приклади: модуль greenlet для Python, бібліотека gevent.

Які варіанти реалізації патерну Singleton у Python

Декоратор:

def singleton(class_):
    instances = {}
    def getinstance(*args, **kwargs):
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        return instances[class_]
    return getinstance

@singleton
class MyClass(BaseClass):
    pass

Метакласи:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class MyClass(BaseClass, metaclass=Singleton):
    pass

Модуль: найпростіший варіант. Переваги: простота. Недоліки: не ініціалізується ліниво.

Які інструменти для перевірки кодстайлу ви знаєте

  • Pycodestyle – перевіряє код на відповідність PEP8.
  • Pylint – поєднав пошук логічних та стилістичних помилок.
  • Flake8 – обгортка до pyflakes, pycodestyle, mccabe.
  • autopep8 – автоматично виправляє код відповідно до PEP8.
  • black – бескомпромісний форматувальник коду.

Що таке list/dict comprehension

Вираз, укладений у квадратні/фігурні дужки, в якому використовуються ключові слова for та in для побудови списку/словника шляхом обробки та фільтрації елементів з одного або кількох ітерованих об'єктів. Спискове включення працює енергійно.

Яка різниця між одинарним та подвійним підкресленням

Є 5 кейсів використання підкреслення в Python:

  1. Для зберігання значення останнього виразу в REPL
  2. Ігнорування значення
  3. Для визначення спеціального значення функції або змінної
  4. Для використання в якості функції локалізації
  5. Для розділення символів числа (1_00 == 100)

Відмінність copy() від deepcopy()

Глибока копія deepcopy() створює нову та окрему копію всього об'єкта або списку з власною унікальною адресою пам'яті. Будь-які зміни, внесені до нової копії, не будуть відображатися в оригіналі.

Поверхневе копіювання copy() також створює окремий новий об'єкт або список, але замість копіювання дочірніх елементів у новий об'єкт воно просто копіює посилання на їх адреси пам'яті.

Що таке garbage collector. У чому його плюси та мінуси

GC (generational garbage collector) – це збирач сміття, який створювався насамперед для виявлення та видалення циклічних посилань.

CPython використовує одразу два алгоритми збирання сміття: підрахунок посилань та generational garbage collector (модуль gc).

Алгоритм підрахунку посилань є фундаментальним і не може бути вимкнений. Циклічний GC є опціональним і може бути вимкнений.

Циклічний збирач сміття розділяє всі об'єкти на 3 покоління (генерації). Нові об'єкти потрапляють у перше покоління. Якщо новий об'єкт виживає після процесу збирання сміття, він переміщається до наступного покоління. Чим вище покоління, тим рідше воно сканується на сміття.

Що таке інтроспекція

Інтроспекція — це здатність програми досліджувати тип або властивості об'єкта під час роботи програми.

class foo(object):
  def __init__(self, val):
    self.x = val
  def bar(self):
    return self.x

dir(foo(5))
=> ['__class__', '__delattr__', ... 'bar', 'x']

Що таке рефлексія

Рефлексія — це здатність комп'ютерної програми досліджувати та модифікувати свою структуру та поведінку (значення, мета-дані, властивості та функції) під час виконання.

# Без рефлексії
Foo().hello()

# З рефлексією
getattr(globals()['Foo'](), 'hello')()

Django

Що таке Middleware, для чого, як реалізується

Middleware – особливий об'єкт, який зазвичай змінює вхідний запит або вихідну відповідь. Наприклад, додає заголовки, робить попередні перевірки. Middleware потрібен, коли потрібно обробити всі запити додатку.

На рівні мови це об'єкт з методами process_request та process_response. Методи мають повернути прийнятий об'єкт (запит або відповідь) для подальшої обробки або кинути виключення, якщо щось не так.

Щоб увімкнути Middleware, достатньо додати шлях до нього в список MIDDLEWARE.

Назвіть основні мідлвари. Навіщо вони потрібні

  • SessionMiddleware – підтримка сесій. Додає до запиту об'єкт session
  • CsrfViewMiddleware – перевіряє, що POST-запити надіслані з поточного домену
  • AuthenticationMiddleware – авторизує користувача. Додає до запиту поле user
  • MessageMiddleware – передає користувачу короткі повідомлення

Опишіть алгоритм роботи CSRF middleware

На кожен запит система генерує унікальний токен та виставляє його в куках. У кожній формі розміщується приховане поле csrf-token з цим же токеном. При надсиланні форми методом POST Django перевіряє, що поле форми та значення в куках збігаються. Якщо ні, це означає, що запит підроблений або надісланий з іншого домену.

Щоб звільнити якусь в'юху від перевірки (якщо це API, наприклад), достатньо обгорнути її декоратором csrf_exempt.

Як реалізується зв'язок m2m на рівні бази даних

Якщо є моделі A та B зі зв'язком багато до багатьох, то створюється таблиця-міст з іменем a_to_b, яка зберігає ключ на A, ключ на B та додаткові відомості. Ця таблиця з'єднується з A та B оператором JOIN.

Чим краще надсилати форму — GET або POST

Форму бажано передавати методом POST з таких причин:

  • GET-запити можуть бути закешовані, особливо в браузерах сімейства IE
  • GET-запити осідають у логах провайдера, сервера, історії браузера. Пароль та логін у такому випадку може засвітитися в багатьох місцях
  • Деякі віруси відстежують вміст адресного рядка та пересилають третім особам.

Як працює Serializer у Django REST Framework

Serializer перетворює інформацію, що зберігається в базі даних та визначену за допомогою моделей Django, у формат, який легко та ефективно передається через API.

Коли користувач передає інформацію через API, серіалізатор бере дані, перевіряє їх та перетворює на щось, що Django може зберегти в екземпляр моделі. Аналогічно, коли користувач звертається до інформації через API, відповідні екземпляри передаються в серіалізатор, який перетворює їх у формат JSON.

class ThingSerializer(serializers.ModelSerializer):
  class Meta:
    model = Thing
    fields = ('name', )

Що таке Meta в класах Django та для чого потрібна

Django значною мірою працює через метакласи. Коли Django конструює ваш клас, вона шукає клас з назвою Meta, щоб знати якісь параметри вашого класу (наприклад модель або поля).

За що відповідає Meta в серіалізаторі

У класі Meta серіалізатора можна задати модель, по якій буде створений серіалізатор, поля, які будуть включені (або exclude для виключення), list_serializer_class тощо.

Як у Django працює система аутентифікації

Django постачається з системою аутентифікації користувачів. Вона забезпечує облікові записи користувачів, групи, права та сесії на основі кук.

Система аутентифікації складається з:

  • Користувачів
  • Прав: Бінарні (так/ні) прапорці, що визначають наявність у користувача права виконувати певні дії.
  • Груп: Загальний спосіб призначення міток та прав на безліч користувачів.
  • Налаштованої системи хешування паролів
  • Інструментів для форм та представлень для аутентифікації користувачів

Веб-розробка

Що таке CGI. Плюси, мінуси

Common Gateway Interface. Угода про те, як веб-сервер взаємодіє з програмою, написаною на якійсь мові. Веб-сервер запускає програму як виконуваний файл. Параметри запиту передаються через змінні оточення.

Плюси: протокол не накладає умов на мову; протокол надзвичайно простий; програма не зберігає стан. Мінуси: запуск процесу ОС на кожен запит дуже повільно; передача даних через stdout повільніша за юнікс-сокети.

Як захистити куки від крадіжки та від підробки

  • Виставляти кукам прапор httponly. Браузер не дасть прочитати та змінити такі куки на клієнті JavaScript'ом.
  • Використовувати прапор secure. Куки будуть передані тільки по захищеному з'єднанню.
  • Встановлювати короткий термін дії куки.
  • Підписувати куки секретним ключем.

Яка різниця між аутентифікацією та авторизацією

Ідентифікація: присвоєння суб'єктам та об'єктам ідентифікатора.

Аутентифікація: перевірка відповідності суб'єкта та того, за кого він намагається себе видати, за допомогою деякої унікальної інформації.

Авторизація: перевірка та визначення повноважень на виконання певних дій відповідно до раніше виконаної аутентифікації.

Всі три процедури взаємопов'язані:

  1. Спочатку визначають ім'я (логін або номер) – ідентифікація
  2. Потім перевіряють пароль (ключ або відбиток пальця) – аутентифікація
  3. І в кінці надають доступ – авторизація

Що таке XSS. Приклади. Як захистити додаток

XSS – міжсайтові запити. Сторінка, схильна до вразливості, змушує користувача виконати запит до іншої сторінки або запустити небажаний JS-код.

Вразливість усувається екрануванням небезпечних символів, чищенням (санацією) HTML-тегів.

REST & SOAP

Що таке REST

REST (Representational state transfer «передача стану представлення») – угода про те, як вибудовувати сервіси. REST визначає 6 архітектурних обмежень:

  1. Єдиноманітність інтерфейсу
  2. Клієнт-сервер
  3. Відсутність стану
  4. Кешування
  5. Шари
  6. Код за вимогою (необов'язкове обмеження)

Що таке SOAP

SOAP – протокол обміну структурованими повідомленнями в розподіленому обчислювальному середовищі. Використовує XML. Може використовуватися з будь-яким протоколом прикладного рівня: SMTP, FTP, HTTP тощо.

У чому різниця між REST та SOAP веб-сервісами

  • REST підтримує різні формати: text, JSON, XML; SOAP – тільки XML
  • REST працює тільки по HTTP(S), а SOAP може працювати з різними протоколами
  • SOAP на основі читання не може бути поміщений у кеш, а REST може
  • SOAP підтримує SSL та WS-security; REST підтримує тільки SSL

HTTP

Як влаштований протокол HTTP

HTTP – текстовий протокол, що працює поверх TCP/IP. HTTP складається із запиту та відповіді.

Стартовий рядок запиту: GET /index.html HTTP/1.1 Стартовий рядок відповіді: HTTP/1.1 200 OK

Заголовки – набір пар ключ-значення. Тіло відповіді може бути порожнім або передавати пари змінних, файли, бінарні дані. Тіло відокремлюється від заголовків порожнім рядком.

Як клієнту зрозуміти, чи вдався запит чи ні

Перевірити статус відповіді:

  • 1xx: використовується вкрай рідко
  • 2xx: запит пройшов успішно
  • 3xx: перенаправлення на інший ресурс
  • 4xx: помилка з вини користувача
  • 5xx: помилка з вини сервера

Що потрібно надіслати браузеру, щоб перенаправити на іншу сторінку

Мінімальна відповідь має мати статус 301 або 302. Заголовок Location вказує адресу ресурсу, на який слід перейти.

Як управляти кешуванням у HTTP

  • Заголовки Cache та Cache-Control регулюють одразу кілька критеріїв кешу.
  • Заголовки Last-Modified та If-Modified-Since задають кешування залежно від дати оновлення документа.
  • Заголовок Etag кешує документ за його унікальним хешем.

Загальне

ООП

Інкапсуляція

Інкапсуляція – механізм мови, що дозволяє об'єднати дані та методи, що працюють з цими даними, в єдиний об'єкт та приховати деталі реалізації від користувача.

Наслідування

Наслідування – механізм мови, який дозволяє описувати новий клас на основі існуючого. Наслідуванню краще надавати перевагу композиції.

Поліморфізм

Поліморфізм має кілька форм:

  • Спеціальний (Ad-Hoc)
  • Параметричний (в деяких мовах представлений дженериками)
  • Поліморфізм підтипів (досягається за допомогою механізмів наслідування та апкасту)

Абстракція

Абстракція говорить, що ми повинні виділяти важливі характеристики об'єкта. Думка в тому, щоб ми могли визначити мінімально необхідний набір цих характеристик для того, щоб можна було вирішити поставлене завдання.

Які принципи програмування ви знаєте

KISS

Принцип Keep It Stupid Simple («Дотримуйся простоти») велить стежити за тим, щоб код залишався якомога простішим.

DRY

Принцип Don't Repeat Yourself («Не повторюйся») нагадує, що кожну поведінку, що повторюється, в коді слід відокремлювати для можливості багаторазового використання.

YAGNI

Принцип You Aren't Gonna Need It («Тобі це не знадобиться») говорить, що небажано залишати в продакшені «точки розширення», призначені тільки для того, щоб дозволити в майбутньому легко додати новий функціонал.

SLAP

Принцип Single Level of Abstraction Principle («Принцип єдиного рівня абстракцій») означає, що функції повинні мати єдиний рівень абстракції.

SOLID принципи

  • S: Single Responsibility Principle – кожен клас повинен вирішувати лише одне завдання.
  • O: Open-Closed Principle – програмні сутності повинні бути відкриті для розширення, але не для модифікації.
  • L: Liskov Substitution Principle – підкласи можуть служити заміною для своїх суперкласів.
  • I: Interface Segregation Principle – створюйте вузькоспеціалізовані інтерфейси для конкретного клієнта.
  • D: Dependency Inversion Principle – об'єктом залежності має бути абстракція, а не щось конкретне.

Що таке code cohesion & code coupling

Зв'язаність модулів (coupling) характеризує ступінь незалежності модулів. При проектуванні систем необхідно прагнути, щоб модулі мали мінімальну залежність один від одного.

Зв'язність (cohesion) характеризує цілісність, «щільність» модуля, тобто наскільки модуль є простим з точки зору його використання. В ідеалі модуль повинен виконувати одну єдину функцію.

Що таке lru cache

LRU (least recently used) — це алгоритм, при якому витісняються значення, які найдовше не запитувалися. Необхідно зберігати час останнього запиту до значення. Як тільки число закешованих значень перевищує N, необхідно витіснити з кешу значення, яке найдовше не запитувалося.

Що таке MQ

Черги повідомлень є зв'язуючою ланкою між різними процесами у ваших додатках та забезпечують надійний та масштабований інтерфейс взаємодії.

Десять причин, чому черги повідомлень є важливим компонентом:

  • Слабке зв'язування
  • Надмірність
  • Масштабованість
  • Еластичність та можливість витримувати пікові навантаження
  • Відмовостійкість
  • Гарантована доставка
  • Гарантований порядок доставки
  • Буферизація
  • Розуміння потоків даних
  • Асинхронний зв'язок

Які готові реалізації MQ ви знаєте

  • ActiveMQ
  • RabbitMQ
  • RedisQueue
  • Kafka
  • rocketMQ
  • zeroMQ

Що таке RPC

Видалений виклик процедур (Remote Procedure Call, RPC) — клас технологій, що дозволяють комп'ютерним програмам викликати функції або процедури в іншому адресному просторі.

Що таке gRPC

gRPC — це високопродуктивний фреймворк від Google для виклику віддалених процедур, що працює поверх HTTP/2. Використовує Protocol Buffers для серіалізації. Підтримує 9 мов: C, C++, Java, Go, Node.js, Python, Ruby, Objective-C, PHP, C#.

Алгоритми, структури

Що таке рекурсія. Які мінуси, плюси

Рекурсія – коли функція викликає саму себе. Логіка рекурсивної функції, як правило, складається з двох гілок: довга гілка викликає цю ж функцію з іншими параметрами, коротка гілка визначає критерій виходу.

Рекурсія, в деяких випадках, спрощує код та робить його декларативним. Неоптимізована рекурсія призводить до накладних витрат ресурсів.

Що таке хвостова рекурсія

Це особливий вид рекурсії, коли функція закінчується викликом самої себе без додаткових операторів. Коли ця умова виконується, компілятор розгортає рекурсію в цикл з одним стек-фреймом.

def fact(N, acc=1):
    if N == 1:
        return acc
    else:
        return fact(N - 1, acc * N)

О-велике при оцінці складності

О-велике описує швидкість роботи алгоритму (не час).

Простий пошук

O(n).

Бінарний пошук

O(log n): працює тільки з відсортованим масивом. Беремо середній елемент та перевіряємо чи він той, що ми шукаємо; якщо ні – відкидаємо половину та повторюємо.

def binary_search(list, item):
  low = 0
  high = len(list) - 1

  while low <= high:
    mid = (low + high) // 2
    guess = list[mid]
    if guess == item:
      return mid
    if guess > item:
      high = mid - 1
    else:
      low = mid + 1
  return None

Швидке сортування

O(n * log n) (середній та найкращий випадок), O(n^2) у найгіршому.

def quicksort(array):
  if len(array) < 2:
    return array
  else:
    pivot = array[0]
    less = [i for i in array[1:] if i <= pivot]
    greater = [i for i in array[1:] if i > pivot]
    return quicksort(less) + [pivot] + quicksort(greater)

Граф

Моделює набір зв'язків. Складається з вузлів та ребер. Бувають направлені та ненаправлені, зважені та незважені.

Пошук у ширину

O(V + E), де V – кількість вершин, E – кількість ребер. Допомагає відповісти на питання: чи існує шлях від вузла A до вузла B? Як виглядає найкоротший шлях від A до B?

Алгоритм Дейкстри

Використовується для знаходження шляху з найменшою вагою у зваженому графі. Працює тільки в направлених ациклічних графах (DAG). Не працює з від'ємними вагами.

Жадібні алгоритми

Використовуються коли обчислення точного рішення займає надто багато часу або коли висока точність не потрібна. Жадібні алгоритми прагнуть до локальної оптимізації з розрахунком на те, що в результаті буде досягнутий глобальний оптимум.

Динамічне програмування

Застосовується для оптимізації деякої характеристики. Працює тільки в ситуаціях, коли задача може бути розбита на автономні підзадачі. У кожному рішенні з області динамічного програмування будується таблиця.

Алгоритм k найближчих сусідів

Застосовується для класифікації та регресії. У ньому використовується перевірка k найближчих сусідів.

Для обчислення відстані до сусіда використовується формула Піфагора або метрика близькості косинусів.

Frontend

Що таке куки. Навіщо вони, як з ними працювати та де вони зберігаються

Куки є інформацією, що зберігається на комп'ютері веб-сайтом. Куки часто зберігають налаштування для веб-сайту. Куки зберігаються в браузері.

З ними можна працювати як з Django (request.COOKIES, response.set_cookie), так і з JavaScript (document.cookie) (якщо не встановлений прапор HTTPONLY).

Чи може сервер змінити (додати, видалити) куки

Так. Значення куки може бути змінене сервером шляхом відправлення нових рядків Set-Cookie: name=newvalue.

Що таке JWT (JSON Web Token)

Веб-токен JSON, або JWT – стандартизований, у деяких випадках підписаний та/або зашифрований формат упаковки даних, який використовується для безпечної передачі інформації між двома сторонами.

JWT визначає особливу структуру інформації, яка надсилається по мережі. Вона представлена в двох формах – серіалізованій та десеріалізованій.

SDLC

Яка різниця між CI та CD

Continuous integration (неперервна інтеграція): всі зміни, що вносяться в код, об'єднуються в центральному репозиторії кілька разів на день, і після кожного злиття спрацьовує автоматична збірка та тестування.

Continuous delivery (неперервна доставка): CI + автоматично готується та ведеться реліз до продакшену. Розгортання в продакшен виконується вручну.

Continuous deployment (неперервне розгортання): CI + CD + повністю автоматизоване розгортання в продакшен.

Яка різниця між Scrum та Kanban

Основна різниця між Scrum та Kanban — у довжині ітерацій. У Scrum ітерації — 2 тижні, у Kanban задачі програмісту можна «підсовувати» хоч кожен день.

У Scrum задачі прийнято оцінювати в Story points або в годинах. У Kanban оцінка не є обов'язковою. Вважається тільки середній час на задачу (Cycle Time).

У Scrum наша ціль — закінчити спринт, у Kanban — задачу.

Що таке Code Debt та як з ним бути

Технічний борг – це усвідомлене компромісне рішення, коли замовник та ключові розробники чітко розуміють всі переваги від швидкого, хоча й не ідеального технічного рішення, за яке доведеться розплатитися пізніше.

Компанії справляються з техборгом трьома способами:

  • Переписують все з нуля.
  • Роблять поступовий рефакторинг.
  • Миряться з техборгом.

VCS

Що таке Git Flow

Historical Branches: замість однієї гілки master використовуються дві: master зберігає офіційну історію релізів, development – активна розробка.

Feature Branches: кожна нова функція розробляється окремо у своїй гілці, яка зливається в development.

Release Branches: коли development набере достатньо функцій для релізу, створюється release-гілка. Після підготовки вона зливається з master та тегується новою версією.

Hotfix Branches: використовуються для швидкого патчингу релізів. Це єдина гілка, що створюється з master.

Що таке Git Rebase

Команда git rebase дозволяє поставити ваші локальні коміти після всіх комітів, що були внесені в гілку. Це дозволяє підтримувати лінійну, чисту історію комітів.

Для інтерактивного rebase (склеювання кількох комітів в один) використовується: git rebase -i HEAD~<кількість_комітів>

Що таке Git Cherry pick

Команда git cherry-pick використовується для перенесення окремих комітів з одного місця репозиторію в інше.

git cherry-pick <commit-hash>

Що таке force push

Якщо ви змінили якісь старі коміти в історії git, при спробі push git видасть помилку. Щоб все ж запушити зміни:

git push --force-with-lease origin <ім'я_гілки>

Цей варіант кращий, оскільки не перезаписує чужі зміни, якщо хтось встиг запушити свої коміти.

Що таке pre-commit check

Хук (hook) pre-commit дозволяє запускати власні сценарії перед створенням коміту. Використовується для:

  • виконання перевірки коду на валідність (наприклад, відповідність PEP8);
  • виконання комплексної перевірки проекту (юніт-тести тощо);
  • переривання операції commit у разі виявлення помилок.

БД

Що таке транзакція. Які у неї є властивості

Транзакція є робочою одиницею роботи з базою даних. Основні концепції (властивості) транзакції описуються абревіатурою ACID:

Атомарність: будь-яка транзакція буде зафіксована тільки цілком. Якщо одна з операцій в послідовності не буде виконана, то вся транзакція буде скасована (rollback).

Узгодженість: будь-яка завершена транзакція фіксує тільки допустимі результати.

Ізольованість: кожна транзакція має бути ізольована від інших, тобто її результат не повинен залежати від виконання інших паралельних транзакцій.

Довговічність: якщо ми отримали підтвердження про виконання транзакції, то зміни не повинні бути скасовані через збій системи.

Які команди управління транзакціями ви знаєте

  • COMMIT: Зберігає зміни
  • ROLLBACK: Відкочує (скасовує) зміни
  • SAVEPOINT: Створює точку, до якої група транзакцій може відкотитися
  • SET TRANSACTION: Розміщує ім'я транзакції

Що таке рівні ізольованості транзакцій. Які вони бувають

Читання зафіксованих даних (read committed):

  • При читанні клієнт бачить тільки зафіксовані дані (ніяких «брудних» операцій читання).
  • При записі можна перезаписувати тільки зафіксовані дані (ніяких «брудних» операцій запису).

Ізоляція знімків стану і відтворюване читання: Кожна транзакція читає дані з узгодженого знімка стану БД на момент її початку.

Серіалізованість (serializability): Найсильніший рівень ізоляції. Гарантує, що навіть при конкурентному виконанні транзакцій результат такий самий, як і у випадку їх послідовного виконання.

Що таке вкладені транзакції

Вкладеними називаються транзакції, виконання яких ініціюється з тіла вже активної транзакції. Завершення транзакції верхнього рівня відкладається до завершення вкладених транзакцій.

Що таке курсор та навіщо він потрібний

Курсор у SQL – це область у пам'яті бази даних, яка призначена для зберігання останнього оператора SQL. Курсори використовуються для вибірки підмножини інформації з бази даних. У кожен момент часу прикладною програмою може бути перевірений один рядок курсора.

Яка різниця між PostgreSQL та MySQL

  • MySQL часто ефективніший при використанні первинного ключа.
  • PostgreSQL підтримує всі нові стандарти SQL, має більш розширений набір функцій (регулярні вирази, рекурсивні запити, успадкування таблиць).
  • MySQL використовує різні рушії для зберігання даних (InnoDB, MyISAM тощо).
  • PostgreSQL підтримує курсори з переміщенням, що дозволяє не завантажувати весь результат у пам'ять клієнта.

Що таке VACUUM в PostgreSQL

VACUUM вивільняє простір, що займається «мертвими» кортежами. При звичайних операціях Postgres кортежі, видалені або застарілі в результаті оновлення, фізично не видаляються з таблиці; вони зберігаються в ній, поки не буде виконана команда VACUUM.

Що таке EXPLAIN. Яка різниця між ним і EXPLAIN ANALYZE

EXPLAIN виводить інформацію про план виконання запиту без його виконання.

EXPLAIN ANALYZE виконує пояснюваний вираз та показує реальні результати виконання, навіть якщо це insert, update або delete.

Які види Join'ів ви знаєте, чим вони відрізняються один від одного

INNER JOIN: для кожного рядка R1 з T1 в результуючій таблиці міститься рядок для кожного рядка в T2, що задовольняє умові з'єднання з R1.

LEFT OUTER JOIN: спочатку виконується INNER JOIN. Потім у результат додаються всі рядки з T1, яким не відповідають жодні рядки в T2, а замість значень стовпців T2 вставляються NULL.

RIGHT OUTER JOIN: спочатку виконується INNER JOIN. Потім у результат додаються всі рядки з T2, яким не відповідають жодні рядки в T1.

FULL OUTER JOIN: спочатку виконується INNER JOIN. Потім додаються рядки без відповідності як з T1, так і з T2.

Дизайн-інтерв'ю

План інтерв'ю

Вважатимемо, що тайм-слот інтерв'ю – 40 хвилин.

  1. Уточнити вимоги та обмеження (4 хвилини)
  2. Зробити оцінки системи (пропускна здатність, скільки потрібно зберігати інформації, кількість серверів тощо) (3 хвилини)
  3. System interface – які сервіси надає система, які сервіси використовує система (3 хвилини)
  4. System high-level design – які компоненти входять в систему, як вони взаємодіють (5 хвилин)
  5. Component detailed design – детальний опис компонентів, визначення вузьких місць (15 хвилин)
  6. Масштабування – як система буде масштабуватися (5 хвилин)
  7. Summary – загальний огляд та презентація рішення (5 хвилин)

1. Збір вимог

Збираємо відповіді на запитання «Що система робить?» та «Якою має бути система?»

2. Оцінки

Для підрахунку оцінок потрібно приблизно уявляти, скільки важить той чи інший тип інформації:

  • Символ – 1 байт
  • Метадані (рядок у базі, вага поста тощо) – 5-10 кілобайт
  • Зображення 1080p – 2 мегабайти
  • Відео 1080p (хвилина) – 30 мегабайт

3. API

Описуємо максимально просто – які методи будуть доступні, які параметри вони приймають.

4. High-level design

Не варто називати конкретні технології, просто описати які компоненти будуть у системі та як вони взаємодіятимуть.

5. Detailed design

  • Описуємо схему БД та запити до неї
  • Перебираємо підходи з обробки даних (pros/cons)
  • Вибираємо рішення та пояснюємо їх tradeoffs
  • Перевіряємо вимоги
  • Визначаємо edge cases

6. Масштабування

Орієнтовна інфраструктура залежно від кількості користувачів:

  • 1 000 користувачів: 1 сервер, 1 БД
  • 10 000: Read replicas, кілька серверів, Load balancer(s)
  • 100 000: Message queue, Rate limits, Cache, CDN
  • 1 000 000: Stateless services, можливо NoSQL, Database sharding
  • 1 000 000 000: Regional DCs

Питання роботодавцю

Питання HR'у

  1. Що з відпусткою та лікарняними?
  2. Чи переноситься відпустка на наступний рік?
  3. Яке ставлення до офіційних державних вихідних?
  4. Чи є медстрахування?
  5. Які обмеження є на період випробувального терміну?
  6. Вільний графік? Чи потрібно знаходитися в офісі n годин?
  7. Як у компанії ставляться до дистанційної роботи?
  8. Чи є у компанії публікації на IT-теми та участь у IT-конференціях?
  9. Чи є мітапи всередині компанії?
  10. Зарплата в якій валюті та чи прив'язана до курсу?

Питання для технічної співбесіди

  1. Як справи з тестуванням? Які тести ви пишете?
  2. Чи є Code Review? Як воно проходить?
  3. Чи є в проектах CI/CD? Чи є DevOps-інженер?
  4. Чи використовуєте ви git-flow?
  5. Чи використовуєте ви методологію розробки (scrum, kanban тощо)?
  6. Чи використовуються системи моніторингу в проектах (Sentry, NewRelic тощо)?
  7. Які БД використовуються в проекті? Чому саме такі?
  8. Яка версія мови Python використовується в проектах?
  9. Чи використовується технологія контейнеризації в проектах?
  10. Чи є сеньйори в команді?
  11. Як у команді приймаються рішення?
  12. Наскільки часто доводиться працювати з legacy?
  13. Які версії Python та фреймворків використовуються?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment