Файл: Учебник по информатике. Программирование на Python. Основы 1 Программирование на Python. Основы.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 03.12.2023
Просмотров: 105
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Открытый учебник по информатике. Программирование на Python. Основы
90
Пример 1.
Генератор квадратов чисел из списка. a = [5, 2, 10, 9] gen = (x*x for x in a) print(list(gen))
# [25, 4, 100, 81]
Данный алгоритм выводит на экран значения, аналогичные следующему алгоритму. gen_list = [] for x in a: gen_list.append(x*x) print(gen_list)
Пример 2.
Генератор целых значений по модулю, считанных из многострочного файла
test.txt. gen = (int(s) if s[0]!='-' else -int(s) for s in open('test.txt')) print(list(gen))
Пояснение: из файла последовательно считываются строки. Если строка не начинается на '-', то возвращаем преобразованную в число строку, в противном случае, возвращаем число, переведенное из строки, с обратным знаком. Или для каждого значения s вычисляется выражение, записанное с помощью тернарного оператора, int(s) if s[0]!='-' else -int(s).
Алгоритм с аналогичным результатом: gen_list = [] for s in open('test.txt'): if s[0] != '-': gen_list.append(int(s)) else: gen_list.append(-int(s)) print(gen_list)
Открытый учебник по информатике. Программирование на Python. Основы
91
Пример 3.
Генератор сумм пар чисел в диапазоне 0..5, в которых хотя бы один элемент кратен 3. gen = (a + b for a in range(5) for b in range(5) if a % 3 == 0 or b % 3 == 0) print(list(gen))
# (0, 1, 2, 3, 4, 1, 4, 2, 5, 3, 4, 5, 6, 7, 4, 7)
Алгоритм с аналогичным результатом: gen_list = [] for a in range(5): for b in range(5): if a % 3 == 0 or b % 3 == 0: gen_list.append(a + b) print(gen_list)
Генератор для пар чисел, где оба числа должны быть кратны трем: gen = (a + b for a in range(5) if a % 3 == 0 for b in range(5) if b % 3 == 0) print(list(gen))
Алгоритм с аналогичным результатом: gen_list = [] for a in range(5): if a % 3 == 0: for b in range(5): if b % 3 == 0: gen_list.append(a + b) print(gen_list)
В данном примере важно заметить одну деталь. Дело в том, что при предварительной проверке на кратность трем значения переменной a алгоритм не будет перебирать значения b, если условие будет ложным. Такой подход позволяет перебирать значения быстрее, не инициализируя вложенный цикл без необходимости.
Открытый учебник по информатике. Программирование на Python. Основы
92
Пример 4.
Генератор для проверки соответствия наборов значений переменных условию
(
???? ∧ ¬???? ∨ ????). from itertools import product gen = (a and not(b) or c for a, b, c in product([0, 1], repeat=3)) print(list(gen))
# (0, 1, 0, 1, True, True, 0, 1)
Но почему получились разные результаты?
Все дело в порядке вычисления. Дело в том, что в случаях, когда имеем случай
a ≠ 1 или b ≠ 0, результат выражения зависит от значения с. Поэтому возвращается значения c. Если же a = 1 и b = 0, то значение a and not (b) равно
True, так как является результатом выполнения логической операции and.
Алгоритм с аналогичным результатом: from itertools import product gen_list = [] for a, b, c in product([0, 1], repeat=3): gen_list.append(a and not(b) or c) print(gen_list)
Открытый учебник по информатике. Программирование на Python. Основы
93
List comprehension и set comprehension
Как можно заметить, генераторы синтаксически объявляются в круглых скобках. При этом такая запись не формирует кортеж, а именно объект генератора-выражения.
В python существует две формы записи для быстрого преобразования возвращаемых генератором значений в список и множество.
При применении вместо круглых скобок квадратных последовательность будет сразу распакована в список (list comprehension, также списковое включение). Такой же приём можно применить и для преобразования в множество (set comprehension).
[выражение_генератора] # список значений
{выражение_генератора} # множество значений
List comprehension и set comprehension помимо удобства использования помогают использовать вычислительные ресурсы эффективнее, чем привычное преобразование через приведение к типу через list(gen) и set(gen).
К сожалению, подобного механизма для кортежей нет, в качестве альтернативы tuple(gen) можно использовать запись через распаковку с помощью операторов астерикса и запятой (без запятой запись не работает).
*(выражение_генератор),
Такая запись соответствует singleton tuple нотации и запаковывает две последовательности (результат работы gen и пустое значение) в кортеж.
Стоит отметить, что такая запись не имеет преимуществ перед приведением через функцию tuple(gen) в плане потребления вычислительных ресурсов.
Подобный принцип также можно использовать и при присвоении значений работы генератора в переменную в виде списка.
*переменная_списка, = (выражение_генератор)
Однако, предпочтительным вариантом сохранения списка, являющимся результатом работы выражения-генератора, является list comprehension.
Открытый учебник по информатике. Программирование на Python. Основы
94
Функции-генераторы
Функции-генераторы – особая разновидность функций, которые ведут себя как итераторы. То есть, при объявлении такой функции создается объект генератор, к которому можно обратиться с помощью функции next.
Осуществляется это с помощью ключевого слова yield.
Пример для иллюстрации.
Создадим функцию-генератор test_gen, которая будет возвращать 3 значения по порядку, например, 5, 2 и 7.
>>>def test_gen(): print('Generate first value') yield 5 print('Generate second value') yield 2 print('Generate third value') yield 7
Для обращения к генератору-функции нужно создать объект генератора функции (такая тавтология).
>>>gen_obj = test_gen()
Что из себя представляет объект и как работает такая функция?
При вызове функции возвращается объект «генератор-функция». Выполнение такой функции «заморожено» в самом начале. Условно можно изобразить такой объект следующим образом, где вертикальная красная черта (далее курсор) определяет место текущего выполнения функции. gen_obj =
1 2 3 4 5 6 7 8
|
print('Generate first value') yield 5 print('Generate second value') yield 2 print('Generate third value') yield 7
После выполнения функции next(gen_obj) выполняются все команды после курсора, включая ближайший вызов оператора yield.
>>>gen_obj(next)
'Generate first value'
5
print('Generate first value') yield 5 print('Generate second value') yield 2 print('Generate third value') yield 7
После выполнения функции next(gen_obj) выполняются все команды после курсора, включая ближайший вызов оператора yield.
>>>gen_obj(next)
'Generate first value'
5
Открытый учебник по информатике. Программирование на Python. Основы
95
При этом объект генератора функции зафиксирует курсор в позиции после первого оператора yield. gen_obj = print('Generate first value') yield 5
|
print('Generate second value') yield 2 print('Generate third value') yield 7
То есть мы видим, что код функции не выполняется до тех пор, пока мы не указываем, что нам необходимо получить следующее значение.
>>>next(gen_obj)
'Generate second value'
2
>>>next(gen_obj)
'Generate third value'
7
Но что будет после того, как генератор вернет все значения? Сейчас наша генератор-функция находится в следующем состоянии. gen_obj = print('Generate first value') yield 5 print('Generate second value') yield 2 print('Generate third value') yield 7
|
При последующем вызове функции next(gen_obj) python будет возвращать код исключения StopIteration.
Следующая конструкция выведет на экран все возвращаемые генератором значения for a in test_gen(): print(a)
Если представить данный код с помощью цикла while и обработки исключения, получим такую запись. gen = test_gen() try: while True: a = next(gen) print(a) except StopIteration: print('Stop iteration')
Открытый учебник по информатике. Программирование на Python. Основы
96
Конструкция try-except выполняет код, описанный в секции try, и в случае возникновения исключения StopIteration печатает на экран фразу ‘Stop
Iteration’.
Конечно же писать подобные генераторы через функции не самый грамотный вариант решения задачи, особенно учитывая наличие выражений-генераторов.
Функции-генераторы применяются для решения задач, где нельзя обойтись простыми генераторами-выражениями.
Например, считывание строк файла, который дозаписывается в процессе его чтения. import time def file_read(filename): f = open(filename) s = '' while s != 'STOP': s = f.readline() if not s: time.sleep(0.1) continue yield s f.close() for line in file_read('test.txt'): print(line.strip())
Зачем нужен такой генератор? Все просто, им очень удобно пользоваться. Да, можно написать подобный код и без генератора, но тогда насколько менее читаемым будет код, где мы совместим алгоритм считывания с ожиданием и обработкой строки. В рассмотренном же случае мы пишем логику считывания файла внутри функции-генератора и используем его внутри цикла for, что разделяет логические части нашего алгоритма.
Открытый учебник по информатике. Программирование на Python. Основы
97
Функции all и any
Очень удобным инструментом совместно с применением генераторов являются функции all и any.
Функция all(итер_объект) проверяет, все ли значения итерируемого объекта истинны, функция any(итер_объект) – истинен ли хотя бы один элемент итерируемого объекта.
Функция all работает по следующей логике: перебираются элементы итерируемого объекта, если найдено значение, соответствующее False (0, пустая строка, пустой список, None), то возвращается False, если таких элементов не найдено возвращается True.
Работу функции all можно проиллюстрировать с помощью следующего кода: def all_func(iter): for x in iter: if not x: return False return True
Функция any работает так: если при переборе встретилось значение, соответствующее значению True, то возвращается True, если таких значений не встретилось, возвращается False. def any_func(iter): for x in iter: if x: return True return False
Также можно использовать данные функции с оператором not.
not any(итер_объект) – все значения ложны,
not all(итер_объект) – хотя бы одно значение ложно.
Открытый учебник по информатике. Программирование на Python. Основы
98
Пример 1.
Все ли целые числа из диапазона [10; 40] удовлетворяют выражению?
????
2
+ 3???? − 10 > 0
Решение с помощью all (выводит True или False) print(all(x**2 + 3x – 10 > 0 for x in range(10, 41)))
Пример 2.
Все ли целые числа, кратные 3 или 5, в диапазоне [100; 150] имеют еще один нечетный делитель, отличный от 1, 3 и 5?
Решение.
Разложим задачу на подзадачи.
Определение кратности 3 или 5 any(x % d == 0 for d in (3, 5))
Определение наличия нечетного делителя – переберем все числа от 7 до х с шагом два, если хотя бы одно число является делителем, вернем True. any(x % d == 0 for d in range(7, x, 2))
Соединяем в одно выражение print(all(any(x % d == 0 for d in range(7, x, 2)) for x in range(100, 151) if any(x % d == 0 for d in (3, 5))))
Открытый учебник по информатике. Программирование на Python. Основы
99
Полезные приемы
Сумма логических значений
Также с помощью выражений-генераторов и понимания, что логический тип наследуется от целочисленного, можно находить количество совпадений с помощью функции sum.
Пример.
Сколько чисел в диапазоне [1000; 10000] делятся на 3, 5 и 7 одновременно?
Решение. sum(all(x % d == 0 for d in (3, 5, 7)) for x in range(1000, 10001))
В итоге получим последовательность из значений True и False, которые при суммировании будут интерпретироваться, как 1 и 0, соответственно.
Аналогично можно воспользоваться функцией нахождения длины для конструкции с list comprehension len( [0 for x in range(1000, 10001) if all(x % d == 0 for d in (3, 5, 7))] )
Так как нет необходимости сохранять все значения для скорости работы можно присвоить всем элементам одно значение, которое уже хранится в памяти.
Открытый учебник по информатике. Программирование на Python. Основы
100
Многомерные списки
Также стоит помнить, что результат работы генератора на каждом этапе возвращает ту структуру, которая описана в левой части выражения. То есть, если указывается кортеж, то генерироваться будет последовательностей кортежей.
Пример.
Составить список значений, который можно получить из чисел 2, 5, 8, 10, 15 путем применения двух команд +2 и *3.
Реализация 1.
Список пар. nums = (2, 5, 8, 10, 15) print([(x + 2, x * 3) for x in nums])
# [(4, 6), (7, 15), (10, 24), (12, 30), (17, 45)]
Реализация 2.
Список значений. nums = (2, 5, 8, 10, 15) print([x + 2 for x in nums] + [x * 3 for x in nums])
# [4, 7, 10, 12, 17, 6, 15, 24, 30, 45]
Реализация 3.
Множество значений (только уникальные значения) nums = (2, 5, 8, 10, 15) print({v for x in nums for v in (x+2, x*3)})
# {4, 6, 7, 15, 10, 24, 12, 30, 17, 45}
Открытый учебник по информатике. Программирование на Python. Основы
101
Список литературы
[1]
«PEP 8 -- Style Guide for Python Code | Python.org,» [В Интернете].
Available: https://www.python.org/dev/peps/pep-0008/. [Дата обращения:
05 09 2021].
[2] «Все, что нужно знать о сборщике мусора в Python / Habr,» [В
Интернете]. Available: https://habr.com/ru/post/417215/. [Дата обращения:
02 09 2021].
[3] «Дополнительный код,»
[В
Интернете].
Available: https://ru.wikipedia.org/wiki/Дополнительный_код. [Дата обращения: 03 09 2021].
[4] «8. Compound statements — Python 3.9.7 documentation,» [В Интернете].
Available: https://docs.python.org/3/reference/compound_stmts.html#grammar-token- if-stmt. [Дата обращения: 05 09 2021].
[5] «8.
Составные операторы,»
[В
Интернете].
Available: https://digitology.tech/docs/python_3/reference/compound_stmts.html#else.
[Дата обращения: 05 09 2021].
[6] «PEP 20 -- The Zen of Python | Python.org,» [В Интернете]. Available: https://www.python.org/dev/peps/pep-0020/. [Дата обращения: 05 09 2021].
[7] «Download
Python | Python.org,» [В Интернете]. Available: https://www.python.org/downloads/. [Дата обращения: 05 09 2021].
[8] «Программная ошибка - ВикипедиЯ,» [В Интернете]. Available: https://ru.wikipedia.org/wiki/Программная_ошибка. [Дата обращения: 05 09 2021].
[9] «Стек вызовов
-
Википедия,»
[В
Интернете].
Available: https://ru.wikipedia.org/wiki/Стек_вызовов. [Дата обращения: 06 09 2021].
[10] «Built-in Types — Python 3.9.7 documentation,» [В Интернете]. Available: https://docs.python.org/3/library/stdtypes.html#common-sequence- operations. [Дата обращения: 10 09 2021].
[11] «List of Unicode Characters of Category “Decimal Number”,» [В
Интернете]. Available: https://www.compart.com/en/unicode/category/Nd.
[Дата обращения: 11 09 2021].
Открытый учебник по информатике. Программирование на Python. Основы
102
[12] «List of Unicode Characters of Category “Other Number”,» [В Интернете].
Available: https://www.compart.com/en/unicode/category/No.
[Дата обращения: 11 09 2021].
[13] «Юникод
-
Википедия,»
[В
Интернете].
Available: https://ru.wikipedia.org/wiki/Юникод. [Дата обращения: 11 09 2021].
[14] «2. Lexical analysis — Python 3.9.7 documentation,» [В Интернете].
Available: https://docs.python.org/3/reference/lexical_analysis.html#string- and-bytes-literals. [Дата обращения: 11 07 2021].
[15] «PEP 3107 -- Function Annotations | Python.org,» [В Интернете]. Available: https://www.python.org/dev/peps/pep-3107/. [Дата обращения: 21 09 2021].
[16] «Wayback
Machine,»
[В
Интернете].
Available: http://web.archive.org/web/20070730120117/http://oakwinter.com/code/type check/. [Дата обращения: 21 09 2021].
[17] «PEP 257 -- Docstring Conventions | Python.org,» [В Интернете]. Available: https://www.python.org/dev/peps/pep-0257/. [Дата обращения: 21 09 2021].
[18] «reStructuredText,»
[В
Интернете].
Available: https://docutils.sourceforge.io/rst.html. [Дата обращения: 21 09 2021].
[19] «PEP 287 -- reStructuredText Docstring Format | Python.org,» [В
Интернете]. Available: https://www.python.org/dev/peps/pep-0287/. [Дата обращения: 21 09 2021].
[20] «PEP 570 -- Python Positional-Only Parameters | Python.org,» [В
Интернете]. Available: https://www.python.org/dev/peps/pep-0570/. [Дата обращения: 21 09 2021].
[21] «ЕГЭ по информатике: генератор вариантов,» [В Интернете]. Available: https://kpolyakov.spb.ru/school/ege/gen.php?action=viewAllEgeNo&egeId=
24&cat155=on&cat156=on&cat164=on. [Дата обращения: 17 09 2021].
[22] «Итерируемый объект, итератор и генератор в Python,» [В Интернете].
Available: https://pythoner.name/iterator. [Дата обращения: 11 09 2021].
Открытый учебник. Программирование на Python © 2021 by Евгений Джобс is licensed under Attribution 4.0 International. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/