Python tests
7.45K subscribers
497 photos
2 videos
45 links
Тесты и задания python разработчиков

По всем вопросам- @notxxx1

@ai_machinelearning_big_data - машинное обучение

@programming_books_it - бесплатные it книги

@pythonl - 🐍

@ArtificialIntelligencedl - AI

@datascienceiot -ds книги
Download Telegram
🧠 Хитрая Python-задача: «Генератор, который взламывает итераторы»
Уровень: 💥 продвинутый (Python 3.12+)

Представьте, что у вас есть ленивый генератор, перебирающий огромный набор данных. Нужно «клонировать» итератор — создать копию, продолжающую работу с того же места, хотя обычные генераторы так не умеют.

🎯 Цель
Напишите cloneable(generator), которая:

● Принимает любую функцию-генератор или итерируемый объект
● Возвращает объект с методом clone(), создающим независимую копию текущего состояния
● Позволяет параллельно вызывать next() у оригинала и всех клонов


gen = cloneable(range(100))
it1 = gen.clone()
it2 = gen.clone()

next(it1) # 0
next(it1) # 1
next(it2) # 0 ← независимая позиция


💡 Ограничения
● Нельзя полностью буферизовать всю последовательность
● Память O(k), где k — число активных клонов
● Только стандартная библиотека; асинхронность не требуется

🔍 Идея решения
● Храним значения в collections.deque по мере чтения из исходного итератора
● Для каждого клона ведём текущий индекс в буфере
● После сдвига всех клонов дальше минимальной позиции — удаляем хвост буфера

Скелет реализации

from collections import deque

class CloneableIterator:
def __init__(self, iterable):
self._source = iter(iterable)
self._buffer = deque()
self._positions = []

def clone(self):
pos = 0
self._positions.append(pos)
idx = len(self._positions) - 1

def _iter():
nonlocal pos
while True:
if pos < len(self._buffer):
yield self._buffer[pos]
else:
try:
val = next(self._source)
except StopIteration:
return
self._buffer.append(val)
yield val
pos += 1
self._positions[idx] = pos
self._shrink()

return _iter()

def _shrink(self):
if not self._positions:
return
min_pos = min(self._positions)
for _ in range(min_pos):
self._buffer.popleft()
self._positions = [p - min_pos for p in self._positions]

def cloneable(iterable):
return CloneableIterator(iterable)


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


gen = cloneable(i**2 for i in range(5))
a = gen.clone()
b = gen.clone()

print(next(a)) # 0
print(next(a)) # 1
print(next(b)) # 0
print(next(b)) # 1
print(next(b)) # 4


Попробуйте улучшить решение:
● Добавьте защиту от «зомби-клонов»
● Реализуйте __length_hint__()
● Или сделайте асинхронную версию acloneable() на базе async for
🐍 Python-задача: что выведет этот код и почему?


def append_to_list(value, my_list=[]):
my_list.append(value)
return my_list

print(append_to_list(1))
print(append_to_list(2))
print(append_to_list(3))


🔍 Варианты:
• a) [1], [2], [3]
• b) [1], [1, 2], [1, 2, 3]
• c) Ошибка исполнения
• d) [1], [2], [3] — но в разных объектах

💡 Разбор:

Аргумент my_list=[]изменяемый объект, созданный один раз при компиляции функции, а не каждый раз при вызове. Поэтому:

- Первый вызов:
my_list = [] → добавили 1[1]
- Второй вызов: та же
my_list, теперь [1] → добавили 2[1, 2]
- Третий: тот же список →
[1, 2, 3]

Правильный ответ: b) `[1]`, `[1, 2]`, `[1, 2, 3]`

🧠 Вывод: никогда не используй изменяемые значения (`list`,
dict, `set`) в аргументах по умолчанию. Это одна из самых частых ловушек в Python.

🛠️ Правильный способ:



def append_to_list(value, my_list=None):
if my_list is None:
my_list = []
my_list.append(value)
return my_list


📌 Теперь каждый вызов будет работать с новым списком.
Forwarded from Python/ django
🐍 Python-задача: что выведет этот код с вложенными генераторами?


gen = (x for x in range(3))

def wrap(g):
return (x * 2 for x in g)

gen2 = wrap(gen)

print(list(gen))
print(list(gen2))


🔍 Варианты:
• a) [0, 1, 2], [0, 2, 4]
• b) [0, 1, 2], []
• c) [], [0, 2, 4]
• d) [0, 1, 2], Ошибка

💡 Разбор:

- `gen = (x for x in range(3))` — генератор 0, 1, 2
- `wrap(gen)` — создаёт **новый генератор**, который берёт значения из `gen` и умножает на 2

Но генераторы **исчерпаемы**: после первого полного прохода `list(gen)` → `gen` становится пустым

Значит:

- `list(gen)` → `[0, 1, 2]`
- `gen2 = wrap(gen)` теперь ссылается на **пустой** `gen`
- `list(gen2)` → `[]`

**Правильный ответ: b) `[0, 1, 2]`, `[]`**

🧠 **Вывод:** если оборачиваешь генератор — не "прожигай" его до передачи дальше. Генераторы нельзя перезапустить или "перемотать".

🛠️ Совет: если данные нужны повторно — сохрани их в список:

```
python
data = list(gen)
```

или используй itertools.tee для разветвления итератора.

@pythonl
Что выедет код ?
This media is not supported in your browser
VIEW IN TELEGRAM
⚙️ Подменяй любые импорты в Python “на лету” — без изменения кода

Если ты хочешь протестировать модуль, подменить зависимость, замокать внешний сервис или обмануть импорт — не обязательно редактировать исходники. Python позволяет перехватывать импорты прямо во время выполнения, через sys.modules.

Вот минимальный приём, который делает это прозрачно:


import sys
import types

# Создаём фейковый модуль
fake = types.SimpleNamespace()
fake.get_data = lambda: "подмена работает"

# Подменяем импорт
sys.modules['external_service'] = fake

# Теперь даже import будет работать
import external_service
print(external_service.get_data()) # → "подмена работает"
🧠 Хитрая задача по Python — что не так с set и списками?

Задача:
Вы хотите получить уникальные элементы из вложенных списков:


items = [[1, 2], [3, 4], [1, 2]]

unique = set(items)
print(unique)


Что произойдёт?

Варианты ответа:
1. Выведется: {[1, 2], [3, 4]}
2. Выведется: [[1, 2], [3, 4]]
3. Произойдёт ошибка
4. Все вложенные списки преобразуются в кортежи и выведутся без дубликатов

Правильный ответ: 3. Произойдёт ошибка

💥 TypeError: unhashable type: 'list'

🔍 Разбор

В Python элементы set должны быть хешируемыми. А списки — изменяемый тип данных, следовательно, не хешируемы.

То есть:


set([[1, 2], [3, 4]])
# вызовет ошибку


Как сделать правильно?

Если вы хотите получить уникальные вложенные списки, можно преобразовать их в кортежи:


items = [[1, 2], [3, 4], [1, 2]]
unique = set(tuple(x) for x in items)
print(unique) # {(1, 2), (3, 4)}


А если хочется вернуть результат обратно в список списков:


result = [list(x) for x in unique]
print(result) # [[1, 2], [3, 4]] (порядок не гарантирован)


⚠️ Вывод

- list нельзя положить в set, dict как ключ — они unhashable
- Используйте tuple для таких случаев
- Уникальность вложенных списков — частый источник багов при работе с JSON, DataFrame, API

📌 Такие мелочи легко упустить, но они выстреливают в самых неожиданных местах. Подписывайся, чтобы не наступать на грабли в одиночку.
Forwarded from Python/ django
🖥 Что выведет код ниже?


def append_to_list(val, my_list=[]):
my_list.append(val)
return my_list

print(append_to_list(1))
print(append_to_list(2))
print(append_to_list(3))


🤯 Подвох
Многие думают, что каждый вызов append_to_list() создаёт новый список, и ожидают вывод:


[1]
[2]
[3]

Но на самом деле Python выведет:


[1]
[1, 2]
[1, 2, 3]

🧠 Почему так происходит?
В Python значения аргументов по умолчанию вычисляются один раз — при определении функции, а не при каждом вызове.

Значение my_list=[] создаётся один раз и сохраняется между вызовами. Это работает как статическая переменная внутри функции.

Как это исправить?
Используй None как значение по умолчанию:


def append_to_list(val, my_list=None):
if my_list is None:
my_list = []
my_list.append(val)
return my_list

print(append_to_list(1)) # [1]
print(append_to_list(2)) # [2]
print(append_to_list(3)) # [3]

💡 Вывод
Не используйте изменяемые объекты (например, list, dict, set) как значения по умолчанию для аргументов функций в Python.


@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет код ?
Каким будет вывод этого кода в консоли?
Anonymous Quiz
7%
{1, 2}
40%
True
17%
False
29%
Это невозможная операция
7%
Посмотреть ответ
Что выведет код ?
Каким будет вывод этого кода?
Anonymous Quiz
4%
5 5 6
39%
5 6 7
42%
5 5 6 7 7 7
2%
5 6 7 7 7
12%
Посмотреть ответ
This media is not supported in your browser
VIEW IN TELEGRAM
🖥 ЗАДАЧА С СОБЕСЕДОВАНИЯ: что выведет код?

Что выведет следующий код — и почему?


a = 256
b = 256
print(a is b)

x = 257
y = 257
print(x is y)


Ожидаешь True в обоих случаях? Не всё так просто.

📌 В Python целые числа от -5 до 256 кешируются.
То есть a и b указывают на один и тот же объект → a is b → True

Но x и y — это уже разные объекты, потому что 257 не кешируется → x is y → False

⚠️ is сравнивает объекты, а не значения.
Если хочешь сравнить значения — используй ==

💡 Вывод: даже базовые типы могут вести себя неожиданно, если сравнивать их через is.
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Python RU
Forwarded from Python RU
Каким будет вывод этого кода?
Anonymous Quiz
53%
[0]
32%
[1]
7%
[1, 0]
5%
[0, 1]
4%
Посмотреть ответ