однострочники пайтон. Однострочники Python лаконичный и содержательный код by Кристи. Однострочники
Скачать 4.44 Mb.
|
Ключевое слово None Ключевое слово None представляет собой константу языка Python и озна- чает отсутствие значения. В других языках программирования, например Java, вместо него используется значение null . Однако null часто вызывает путаницу, особенно у начинающих программистов, считающих, что оно равно целочисленному значению 0 . Поэтому в языке Python используется ключевое слово None , как показано в листинге 1.6, чтобы четко обозначить его отличие от числового значения 0 , пустого списка и пустой строки. Любо- пытно, что значение None — единственное значение в типе данных NoneType В этом коде приведено несколько примеров типа данных None (а также по- казано, чем он не является). Если не описать для функции возвращаемое значение, то по умолчанию будет возвращаться None Контейнерные структуры данных 27 Листинг 1.6. Ключевое слово None def f(): x = 2 # С ключевым словом 'is' я познакомлю вас ниже print(f() is None) # True print("" == None) # False print(0 == None) # False Контейнерные структуры данных Python включает контейнерные типы данных, позволяющие легко и эффек- тивно осуществлять сложные операции. Списки Список (list) — это контейнерный тип данных, предназначенный для хране- ния последовательности элементов. В отличие от строк, списки изменяемые (mutable), их можно модифицировать во время выполнения. Что такое тип данных список, удобнее всего показать на примерах: l = [1, 2, 2] print(len(l)) # 3 Этот фрагмент кода демонстрирует создание списка и заполнение его тремя целочисленными элементами с помощью квадратных скобок. Как видите, в списке могут быть повторяющиеся элементы. Функция len() возвращает количество элементов в списке. Ключевое слово: is Ключевое слово is просто проверяет, ссылаются ли две переменные на один объект в памяти. Новичков, у которых нет опыта работы с Python, оно может привести в замешательство. В листинге 1.7 мы проверяем, ссылаются ли два целых числа и два списка на одни и те же объекты в памяти. 28 Глава 1. Краткая памятка по Python Листинг 1.7. Ключевое слово is y = x = 3 print(x is y) # True print([3] is [3]) # False Если создать два списка (даже состоящих из одних и тех же элементов), то они будут ссылаться на два различных объекта-списка в памяти. Модифика- ция одного из этих объектов никак не повлияет на второй. Списки — изменя- емые, поскольку их можно модифицировать после создания. Следовательно, если проверить, ссылаются ли два списка на один объект в памяти, результат будет равен False . А целочисленные значения — неизменяемые, так что нет риска случайно изменить через объект одной переменной значения всех остальных переменных. Объект 3 типа integer нельзя изменить, поскольку такая попытка просто приведет к созданию нового объекта integer, а старый останется неизменным. Добавление элементов Язык Python предлагает три основных способа добавления элементов в уже существующий список: добавление в конец списка, вставка и конкатенация списков. # 1. Добавление в конец списка l = [1, 2, 2] l.append(4) print(l) # [1, 2, 2, 4] # 2. Вставка l = [1, 2, 4] l.insert(2, 3) print(l) # [1, 2, 3, 4] # 3. Конкатенация списков print([1, 2, 2] + [4]) # [1, 2, 2, 4] В результате всех трех операций получается один и тот же список [1, 2, 2, 4] . Но операция append выполняется быстрее всего, поскольку не тре- бует ни обхода списка для вставки элементов в нужное место (как в случае insert ), ни создания нового списка на основе двух подсписков (как в случае Контейнерные структуры данных 29 конкатенации списков). Если не вдаваться в подробности, то операцию insert имеет смысл использовать только для добавления элемента в конкретное место списка, причем не в конце, а конкатенацию — для конкатенации двух списков произвольной длины. Обратите внимание, что существует и четвер- тый метод, extend() . Он служит для добавления в конец списка нескольких элементов сразу наиболее эффективным способом. Удаление элементов Элемент x можно легко удалить из списка с помощью метода remove(x) списка: l = [1, 2, 2, 4] l.remove(1) print(l) # [2, 2, 4] Этот метод работает с самим объектом списка, а не создает новый, изме- ненный список. В предыдущем примере кода мы создали объект списка l и удалили из него элемент. Такой подход не требует избыточных копий данных списка, позволяя экономить память. Инвертирование списков Порядок элементов списка можно инвертировать с помощью метода list.re verse() : l = [1, 2, 2, 4] l.reverse() print(l) # [4, 2, 2, 1] Инвертирование списка приводит к модификации исходного объекта списка, а не просто создает новый объект списка. Сортировка списков Отсортировать элементы списка можно с помощью метода list.sort() : l = [2, 1, 4, 2] l.sort() print(l) # [1, 2, 2, 4] 30 Глава 1. Краткая памятка по Python Опять же, сортировка списка приводит к модификации исходного объекта списка. Полученный в результате список отсортирован в порядке возрас- тания. Содержащие строковые объекты списки сортируются в порядке лексикографического возрастания (от 'a' до 'z' ). В общем случае функция сортировки предполагает, что объекты сравнимы. В общих чертах, если для объектов a и b произвольного типа данных можно вычислить a > b , то Python может отсортировать список [a, b] Индексация элементов списков Узнать индекс заданного элемента списка x можно с помощью метода list. index(x) : print([2, 2, 4].index(2)) # 0 print([2, 2, 4].index(2,1)) # 1 Метод index(x) ищет первое вхождение элемента x в списке и возвращает его индекс. Как и другие основные языки программирования, Python при- сваивает индекс 0 первому элементу, а индекс i – 1 — i-му элементу. Стеки Структура данных стек (stack) работает по интуитивно понятному принципу «последним поступил, первым обслуживается» (last in, first out, LIFO). Стек аналогичен стопке документов: новые помещаются сверху старых, и по мере работы с этой стопкой первым обрабатывается самый верхний документ. Стек — по-прежнему одна из базовых структур данных в computer science, используемая при управлении операционными системами в алгоритмах, при синтаксическом разборе и поиске с возвратом. Списки Python могут вполне интуитивным образом играть роль стеков: при использовании операции append() для добавления элемента в стек, а pop() — для удаления последнего добавленного элемента. stack = [3] stack.append(42) # [3, 42] stack.pop() # 42 (stack: [3]) stack.pop() # 3 (stack: []) Контейнерные структуры данных 31 Благодаря эффективности реализации списков обычно можно обойтись без импорта внешних библиотек стеков. Множества Структура данных множество (set) — простейший тип коллекций в Python и многих других языках программирования. Многие популярные языки, предназначенные для распределенных вычислений (например, MapReduce и Apache Spark), практически исключительно сосредоточиваются на опера- циях с множествами как простыми типами данных. Что же такое множество? Множество — неупорядоченная коллекция уникальных элементов. Разобьем это определение на составные части. Коллекция Множество — коллекция элементов подобно спискам и кортежам. Кол- лекция состоит либо из элементов простых типов данных (целочисленных значений, значений с плавающей точкой, строковых значений), либо из более сложных элементов (объектов, кортежей). Однако все типы данных в множестве должны быть хешируемыми, то есть обладать соответствующим хеш-значением. Хеш-значение объекта никогда не меняется и используется для его срав- нения с другими объектами. Рассмотрим пример в листинге 1.8, где мно- жество создается на основе трех строковых значений, после проверки их хеш-значений. Далее пробуем создать множество списков, но это нам не удается, поскольку списки нехешируемые. Листинг 1.8. Множество требует хешируемых элементов hero = "Harry" guide = "Dumbledore" enemy = "Lord V." print(hash(hero)) # 6175908009919104006 print(hash(guide)) # -5197671124693729851 ## Можно ли создать множество строковых значений? characters = {hero, guide, enemy} print(characters) # {'Lord V.', 'Dumbledore', 'Harry'} 32 Глава 1. Краткая памятка по Python ## Можно ли создать множество списков? team_1 = [hero, guide] team_2 = [enemy] teams = {team_1, team_2} # TypeError: unhashable type: 'list' Множество строковых значений можно создать, поскольку строковые значения — хешируемые. А создать множество списков нельзя, поскольку списки нехешируемые. Дело в том, что хеш-значение зависит от содержимого элемента коллекции, а списки — изменяемые; если модифицировать данные в списке, то хеширование тоже должно измениться. А поскольку изменяемые типы данных нехешируемы, использовать их в множествах нельзя. Неупорядоченность В отличие от списков, у элементов множества нет четко заданного порядка. Вне зависимости от очередности помещения данных в множество, никогда нельзя быть уверенным, в каком порядке они будут храниться в множестве. Вот пример: characters = {hero, guide, enemy} print(characters) # {'Lord V.', 'Dumbledore', 'Harry'} Я вставил в множество сначала героя, но мой интерпретатор вывел первым антагониста (интерпретатор Python — явно на стороне зла). Учтите, что ваш интерпретатор может вывести элементы множества в отличном от моего порядке. Уникальность Все элементы множества должны быть уникальными. Строгое определение выглядит следующим образом: для всех пар значений x, y из множества при x!=y хеш-значения также отличаются: hash(x)!=hash(y) . А поскольку все значения в множестве различны, создать армию Гарри Поттеров для войны с лордом В. не получится: clone_army = {hero, hero, hero, hero, hero, enemy} print(clone_army) # {'Lord V.', 'Harry'} Неважно, сколько раз вставляется одно значение в одно и то же множество, все равно в нем будет сохранен только один экземпляр этого значения. Дело Контейнерные структуры данных 33 в том, что у всех этих героев одно хеш-значение, а множество может содер- жать не более одного элемента с одинаковым хеш-значением. Существует расширение такой структуры данных , как множество, — мультимножество, в котором можно хранить несколько экземпляров одного значения. На прак- тике, впрочем, оно используется редко. А обычные множества, напротив, встречаются практически в коде любого нетривиального проекта — например, для пересечения множества заказчиков и множества посетителей магазина, в результате чего будет возвращено новое множество заказчиков, которые также заходили в магазин. Ассоциативные массивы Ассоциативный массив — удобная структура данных для хранения пар (ключ, значение) : calories = {'apple' : 52, 'banana' : 89, 'choco' : 546} Читать и записывать элементы можно путем указания ключа в квадратных скобках: print(calories['apple'] < calories['choco']) # True calories['cappu'] = 74 print(calories['banana'] < calories['cappu']) # False Для доступа ко всем ключам и значениям ассоциативного массива служат функции keys() и values() соответственно: print('apple' in calories.keys()) # True print(52 in calories.values()) # True Для доступа к парам (ключ, значение) ассоциативного массива служит метод items() : for k, v in calories.items(): print(k) if v > 500 else None # 'choco' 34 Глава 1. Краткая памятка по Python Таким образом, можно легко проходить в цикле по всем ключам и значениям массива, не обращаясь к ним по отдельности. Принадлежность Для проверки того, содержит ли множество, список или ассоциативный массив определенный элемент, служит ключевое слово in (листинг 1.9). Листинг 1.9. Ключевое слово in print(42 in [2, 39, 42]) # True print("21" in {"2", "39", "42"}) # False print("list" in {"list" : [1, 2, 3], "set" : {1,2,3}}) # True С помощью ключевого слова in можно выяснить, содержится ли целочис- ленное значение 42 в списке целочисленных значений, или проверить при- надлежность строкового значения "21" множеству строковых значений . Если x встречается в коллекции y, то мы будем говорить, что x — элемент коллекции y. Проверка принадлежности элемента множеству выполняется быстрее, чем проверка принадлежности элемента списку: чтобы проверить наличие элемента x в списке y, необходимо обходить весь список до тех пор, пока не будет найден элемент x или не будут проверены все элементы. Множества же реализованы аналогично ассоциативным массивам: для проверки наличия элемента x в множестве y Python «под капотом» выполняет одну операцию y[hash(x)] и проверяет, не равно ли None возвращаемое значение. Списковые включения и включения множеств Списковое включение — популярная возможность Python, с помощью кото- рой можно быстро создавать и модифицировать списки. Оно описывается простой формулой [выражение + контекст] : выражение указывает Python, что делать с каждым из элементов списка; контекст указывает Python, какие элементы списка брать. Контекст состоит из произвольного количества операторов for и if Управляющие конструкции 35 Например, в операторе спискового включения [x for x in range(3)] первая часть x — это выражение (идентификатор), а вторая часть for x in range(3) — контекст. Данный оператор создает список [0, 1, 2] . Функция range() при использовании с одним аргументом, как в нашем примере, возвращает диа- пазон последовательных целочисленных значений 0 , 1 и 2 . Ниже представлен еще один пример кода для спискового включения: # (имя, $-доход) customers = [("John", 240000), ("Alice", 120000), ("Ann", 1100000), ("Zach", 44000)] # Ценные клиенты, зарабатывающие более $1 млн whales = [x for x,y in customers if y>1000000] print(whales) # ['Ann'] Включения для множеств аналогичны списковым включениям, только соз- дается множество, а не список. Управляющие конструкции Управляющие конструкции позволяют принимать в коде различные решения. Алгоритмы часто сравнивают с кулинарными рецептами, состоящими из последовательного списка команд: положить в кастрюлю рис, залить холод- ной водой, посолить, отварить, подать рис на стол. Без условных операторов выполнение последовательности команд заняло бы лишь несколько секунд, и рис, конечно, не сварился бы, поскольку вы бы, например, налили воду, посолили, положили рис, а потом сразу же подали его, не дожидаясь, пока вода закипит, а рис сварится. В различных ситуациях необходимо реагировать по-разному: рис необходимо класть в кастрюлю, только если вода уже нагрелась, а подавать его, только если он уже мягкий. Практически невозможно писать программы так, чтобы преду- смотреть все детерминированные события реального мира. Вместо этого не- обходимо писать программы, по-разному реагирующие на различные условия. Ключевые слова if, else и elif С помощью ключевых слов if , else и elif (листинг 1.10) можно произво- дить условное выполнение различных ветвей кода. 36 Глава 1. Краткая памятка по Python Листинг 1.10. Использование ключевых слов if, else и elif x = int(input("your value: ")) if x > 3: print("Big") elif x == 3: print("Medium") else: print("Small") Получаем сначала вводимые пользователем данные, преобразуем их в целое число и сохраняем их в переменной x . Затем проверяем, не превышает ли , не равно ли или меньше 3 значение переменной. Другими сло- вами, код различным образом реагирует на непредсказуемые реалистичные входные данные. Циклы Для повтора выполнения фрагментов кода в Python существует два типа циклов: цикл for и цикл while . С их помощью можно легко написать за- нимающую всего две строки кода программу, которая будет выполняться бесконечно. Реализовать подобный повтор выполнения иным способом будет непросто (в качестве альтернативы можно воспользоваться рекурсией). В листинге 1.11 показаны в действии оба варианта циклов. Листинг 1.11. Ключевые слова for и while # Объявление цикла for for i in [0, 1, 2]: print(i) ''' 0 1 2 ''' # Цикл while — аналогичная семантика j = 0 while j < 3: print(j) j = j + 1 ''' 0 1 2 ''' Управляющие конструкции 37 Оба варианта циклов выводят целые числа 0 , 1 и 2 в командную оболочку, но делают это по-разному. Цикл for объявляет переменную цикла i , принимающую последовательно все значения из списка [0, 1, 2] . Его выполнение продолжается, пока зна- чения не закончатся. При использовании цикла while тело цикла выполняется до тех пор, пока не будет выполнено заданное условие — в данном случае, пока j < 3 Существуют два основных способа выхода из цикла: можно задать условие цикла, которое рано или поздно станет равно False , либо воспользоваться ключевым словом break в конкретном месте тела цикла. Пример второго варианта приведен в листинге 1.12. Листинг 1.12. Ключевое слово break while True: break # цикл не бесконечный print("hello world") # hello world Мы создали цикл while с условием, тождественно равным True . Так что, на первый взгляд, кажется, будто он будет выполняться бесконечно. Бесконеч- ный цикл while — распространенная практика при, например, разработке веб-серверов, бесконечно повторяющих процедуру ожидания нового веб- запроса и его обработки. Однако в некоторых случаях бывает нужно досрочно прервать выполне- ние цикла. В примере с веб-сервером имеет смысл приостановить выдачу файлов из соображений безопасности, если сервер подвергается атаке. В подобных случаях можно воспользоваться ключевым словом break для выхода из цикла и выполнения следующего за ним кода. В приведенном выше листинге 1.12 после досрочного завершения цикла выполняется print("hello world") Можно также приказать интерпретатору Python пропустить определенные части цикла, не прибегая к досрочному выходу из него. Например, вместо полного останова веб-сервера пропустить вредоносные веб-запросы. Реали- зовать это можно с помощью оператора continue , завершающего выполнение текущей итерации цикла и возвращающего выполнение обратно к условию цикла (листинг 1.13). |