Python: задачки и вопросы
7.79K subscribers
1.18K photos
1 video
1 file
87 links
Вопросы и задачки для подготовки к собеседованиям и прокачки навыков

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/media
Download Telegram
Понятия итерируемых объектов и списковых включений были объединены в инструмент — генераторные выражения. Синтаксически они похожи на нормальные списковые включения и поддерживают весь их синтаксис, в том числе фильтры if и вложение циклов, но они помещаются в круглые скобки, а не в квадратные (подобно кортежам объемлющие круглые скобки часто необязательны):


>>> (х ** 2 for х in range(4)) # Генераторное выражение создает итерируемый объект
... <generator object <genexpr> at 0x10250ab50>


Для принудительного вырабатывания всех результатов сразу можно использовать list():


>>> list(x ** 2 for х in range(4))
... [О, 1, 4, 9]
В задаче используется генератор, и происходит разбивка строки по запятой.

1. Разбивка строки:


"ааа,bbb,ссс".split(",") # ["ааа", "bbb", "ссс"]


Этот метод разбивает строку на список строк по разделителю.

2. Генератор:


(х + "\n" for х in ...)


Здесь создается генератор, который перебирает каждую строку из полученного списка ["ааа", "bbb", "ссс"] и добавляет к каждой строке символ новой строки "\n":

— Для х = "ааа" будет "ааа\n"
— х = "bbb" будет "bbb\n"
— Для х = "ссс" будет "ссс\n"

3. Распаковка значений:


а, b, с = (х + "\n" for х in "ааа,bbb,ссс".split(","))


В этом выражении используется распаковка, чтобы присвоить значения переменным а, b и с. Генератор будет предоставлять значения по одному:

— а получит значение "ааа\n"
— b получит значение "bbb\n"
— с получит значение "ссс\n"
Какого метода в pandas не существует?
Anonymous Quiz
6%
pd.read_excel
25%
pd.read_parquet
25%
pd.read_docx
45%
Все существуют
В каких контекстах может появиться генераторное выражение?
Anonymous Quiz
17%
Циклы for
7%
Функции sum, map, sorted
3%
Функции any, all, list
72%
Все вышеперечисленное
Генераторные выражения вместо построения результирующего списка в памяти возвращают объект генератора — автоматически созданный итерируемый объект. В свою очередь этот итерируемый объект поддерживает протокол итерации, чтобы выдавать по одной порции результирующего списка за раз в любом итерационном контексте.

Итерируемый объект также сохраняет состояние генератора, пока он действует — переменную х в предшествующих выражениях наряду с местоположением в коде генератора. Мы получаем обратно объект, который запоминает оставленное им место после возвращения каждой части результата:


G = (х ** 2 for х in range (4))
next(G) is G # 0
next(G) is G # 1
next(G) is G # 4
next(G) is G # 9
next(G) is G # Остановка итерации


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


for num in (х ** 2 for х in range (4)): # Автоматически вызывает next ()
print (’%s, %s’ % (num, num / 2.0))


Так поступает каждый итерационный контекст: циклы for, встроенные функции sum, map и sorted, списковые включения и другие итерационные контексты, в том числе встроенные функции any, all и list. Будучи итерируемыми объектами, генераторные выражения могут появляться в любом итерационном контексте подобного рода в точности как результат вызова генераторной функции.
Какой код исполнится медленнее остальных?
Anonymous Quiz
30%
1
43%
2
19%
3
9%
Скорость исполнения случайна
Приведенное далее списковое включение производит такой же результат, как показанные после него эквиваленты в форме тар из Python З.Х и генераторов, но создает два физических списка; остальные генерируют только по одному целому числу за раз с помощью вложенных генераторов, а форма генераторного выражения может более четко отражать свое намерение:


[х * 2 for х in [abs(x) for x in (-1, -2, 3, 4)]] # Вложенные включения

list(map(lambda x: x * 2, map(abs, (-1, -2, 3, 4)))) # Вложенные отображения

list(x * 2 for x in (abs(x) for x in (-1, -2, 3, 4))) # Вложенные генераторы


Хотя результатом всех трех форм является объединение операций, генераторы делают это, не создавая множество временных списков.
В версии Python 3.3 и выше есть расширенный синтаксис для оператора yield, который делает возможным делегирование работы подгенератору с помощью конструкции from генератор. В простых ситуациях он эквивалентен выдаче в цикле for — в следующем коде вызов list заставляет генератор выпустить все свои значения, а включение в круглых скобках является генераторным выражением:


def both(N):
for i in range(N): yield i
for i in (x ** 2 for x in range(N)): yield i

print(list(both(5))) # [0, 1, 2, 3, 4, 0, 1, 4, 9, 16]
Аргументы со звездочкой способны распаковывать итерируемый объект в индивидуальные аргументы. Однако в нашем примере также присутствует генератор.


def f(a, b, c):
print('%s, %s и %s' % (a, b, c))

# Распаковка значений генераторного выражения
f(*(i for i in range(3)))


Генераторы вместо построения результирующего списка в памяти возвращают итерируемый объект. Прием применим также к словарям и представлениям:


D = dict(а='Bob', b='dev', с=40.5)

# Нормальные ключевые аргументы
f(a='Bob’, b='dev’, с=40.5) # Bob, dev и 40.5

# Распаковка словаря: ключ=значение
f(**D) # Bob, dev и 40.5

# Распаковка итератора ключей
f(*D) # b, c и a

# Распаковка итератора представления
f(*D.values()) # Bob, dev и 40.5\nNone


None выводится, потому что это означает последний шаг итерирования (StopIteration). Подробнее про это читайте в этом посте.