Списки и словари по Марку Лутцу

Данная статья имеет очень важное значение. Она особенно важна тем, что списки и словари являются важнейшими типами данных, которые используются в веб-программировании, анализе данных, парсинге сайтов и других решений на Python.

Друзья, кто меня читает, прошу обратить на эту тему особое внимание. Так что Attention!

Списки и словари по Марку Лутцу

Что важно знать про списки?

Списки - это коллекция значений

М. Лутц

Списки - это наиболее гибкий тип, который используется для помещения числовых и текстовых данных в единую структурную форму. Кроме того, они способны содержать и внутренние списки.

myBirthList = ['Vasya', 'Masha', 'Bob', 'Sam'] # cписок с именами ages = [17, 20, 23, 24] # возраст ( обратите внимание, тут кавычек нет) agesBirthList = ['Vasya', 'Masha', 'Bob', 'Sam', [17, 20, 23, 24]] # возраст+ имена

Последнее представление данных считается не совсем верным с точки зрения логики. В нём демонстрируется только возможности списков.

Какими характеристиками обладает список?

1) Упорядоченная коллекция произвольных объектов. ( Список - место накопления других объектов)

2) Поддерживают доступ по смещению (вспоминаем индексацию).

3) Имеют разнородную переменную длину и допускает произвольное глубокое вложение (они способны увеличиваться, уменьшаться на месте, содержать разные типы данных.

4) Это изменяемая последовательность ( подтверждается, что списки - это изменяемые последовательности)

5) Список - характеристика массива ссылок на объекты ( в случае присваивания объект сохраняет ссылку на тот же самый объект, а не его копию).

Какие ещё существуют списковые операции?

fruit = list('apple') # ['a', 'p', 'p', 'l', 'e'] numbers = list(range(3,10)) # [3, 4, 5, 6, 7, 8, 9] OneNumberFromListNumbers = numbers[3] # 6 SliceNumbers = numbers[1:5] # [4, 5, 6, 7] print(len(numbers)) # количество элементов в списке newListNumbers = numbers+SliceNumbers # [3, 4, 5, 6, 7, 8, 9, 4, 5, 6, 7] конкатинация otherList = OneNumberFromListNumbers*SliceNumbers # ещё один пример конкатинации for i in numbers: print(i) # списки поддерживают итерацию numbers.append(1000) # единичная вставка print(numbers) # [3, 4, 5, 6, 7, 8, 9, 1000] numbers.extend([10000, 20000, 30000]) # [3, 4, 5, 6, 7, 8, 9, 1000, 10000, 20000, 30000] множественная вставка numbers.insert(0, 20) print(numbers) # [20, 3, 4, 5, 6, 7, 8, 9, 1000, 10000, 20000, 30000] print(numbers.count(1000)) # подсчёт количество элементов в списке

Рекомендую копировать и вставлять код построчно, чтобы смотреть что получается. В тех примерах, где описано присваивание, результат выполнения операции можно осуществить с помощью print()

fruit = list('apple') print(fruit) # ['a', 'p', 'p', 'l', 'e']

Более подробно о том, какие операции выполняют списки можно найти в официальной документации Python. Для работы со списками можно пройти по следующей. Если не понятна официальная документация, то альтернативным источником может являться другая ссылка .Также не забываем про справку dir() или help()

Какие могут быть сложные случаи?

1) List Comprehention

Сложным случаем использования списком является list comprehention. Дословного перевода на русский язык я не нашёл, поэтому оставляю тут английский вариант.

rangeList = [i for i in range(2,5)] # [2, 3, 4]

Суть данного примера состоит в том, что мы используем вложенный цикл for внутри списка. Такая форма записи эквивалентна следующему коду:

rangeList = [] for i in range(2,5): rangeList.append(i) print(rangeList) # [2, 3, 4]

То есть первый случай является сжатой формой второго случая. Однако на начальных этапах я рекомендую пользоваться вторым, он более понятный или читабельный.

2) Использование map()

Про служебное слово map() можно прочитать из официальной документации. Формально оно необходимо для изменения данных в списке без объявления специального цикла for. Ниже приведу пример.

Например, вот дан нам список со значениями:

myList = [-2, 3, 4, 5, 7, -20]

И нам дали такое задание: заменить отрицательные значения на положительные. Недолго думая, я решил применить модуль к каждому символу через функцию map()

answer = list(map(abs, myList)) print(answer) # [2, 3, 4, 5, 7, 20]

Обязательно следует принять во внимание, что перед вызовом map необходимо объявлять ожидаемый тип данных, в противном случае интерпретатор не сможет вывести нужные значения.

myList = [-2, 3, 4, 5, 7, -20] answer = map(abs, myList) print(answer) # <map object at 0x0000007C4EC3BAF0>

Индексация, нарезание и массивы

В Python не существует такого понятия как массивы, поэтому список может определяться как список, а может как массив. Для того, чтобы написать массив, необходимо вложить во вложенный список другой список. В качестве значений списка массива определяются числа. В общем виде массив определяется вот так.

array = [ [10, 11 ,12], [13, 14, 15], [16,17,18 ] ] print(array[0]) # Первая строка print(array[0][2]) #Третье число первой строки print(array[-1]) #Третья строка

Изменение значений в списке на месте

В начале главы было сказано, что значения в списках в Python можно изменять. Давайте продемонстрирую это на примере. Допустим у нас есть следующий список

FruitList = ['banana', 'apple', 'potatoes']

При анализе списка мы заметили, что список долен содержать фрукты, однако в данных допущена ошибка 'potatoes' (картофель). Давайте заменим картофель на ананас.

FruitList[2]= 'pineapple' print(FruitList) # ['banana', 'apple', 'pineapple']

Таким образом мы заменили картофель на ананас. Также можно изменять и добавлять данные через срезы.

Попробуйте применить замену значений в списках к числам. Рекомендую думать над тем, что вы ожидаете получить и что получаете. И потом сравнивайте получаемое значение с ожидаемым. Если ответы сходятся, значит индексация стала более-менее понятна.

Немного про сортировку

У списка есть один очень замечательный метод, который очень часто спрашивают на собеседованиях. Называется sort()

Вопрос из собеседования:

Чем отличается list.sort() от sorted?

Ответ: метод sort() позволяет отсортировать значения списка на месте, а для Sorted(list) требуется выделять отдельную переменную.

Давайте потренируемся.

1) Пример - сортировка без аргументов

listnames = ['Misha', 'Alexandr', 'Alexandra', 'Masha', 'Alexei'] listnames.sort() print(listnames) # ['Alexandr', 'Alexandra', 'Alexei', 'Masha', 'Misha']

2) Пример - сортировка с аргументами

listWords = ['AbC', 'ABC', 'ABc', 'aBc', 'abc'] listWords.sort(key=str.lower) # Сортировка по нижнему регистру print(listWords) # ['AbC', 'ABc', 'aBc', 'abc', 'ABC']

3) Пример сортировка с помощью sorted()

listnames = ['Misha', 'Alexandr', 'Alexandra', 'Masha', 'Alexei'] sortedNames = sorted(listnames) print(sortedNames) # ['Alexandr', 'Alexandra', 'Alexei', 'Masha', 'Misha']
listnames = ['Misha', 'Alexandr', 'Alexandra', 'Masha', 'Alexei'] SortedNames = listnames.sort() print(SortedNames) #None

Немного про удаление

В списках можно как добавлять значения, так и удалять. За удаление отвечает методы: pop() , remove() и служебный оператор del

1) Пример pop()

Метод pop() удаляет значения исходя из его индекса и возвращает в консоль удалённое слово.

listnames = ['Misha', 'Alexandr', 'Alexandra', 'Masha', 'Alexei'] listnames.pop(0) # Удаление и возврат элемента (вернёт 'Misha') print(listnames) # ['Alexandr', 'Alexandra', 'Masha', 'Alexei']

2) Пример remove()

Метод remove() удаляет значение по заранее заданному значению в качестве аргумента, только здесь он НЕ возвращает полученное значение. Всё тот же пример с именами :)

listnames = ['Misha', 'Alexandr', 'Alexandra', 'Masha', 'Alexei'] listnames.remove('Alexandr') print(listnames) # ['Misha', 'Alexandra', 'Masha', 'Alexei']

3) Пример del

Del является уже служебным словом и допускает удаление значения по его индексу.

listnames = ['Misha', 'Alexandr', 'Alexandra', 'Masha', 'Alexei'] del listnames[0] print(listnames) # ['Alexandr', 'Alexandra', 'Masha', 'Alexei']

Теперь со списками я закончил и перехожу к словарям.

Что важно знать про словари?

Словарь - неупорядоченная коллекция, которая отличается от списка тем, что элементы сохраняются и извлекаются по ключу, а не по позиционному смещению.

М. Лутц

Друзья, а давайте вспомним школьные годы уроки английского языка. Помните, что для того, чтобы заучить какие-то слова, каждый из нас составлял словарь из незнакомых слов. А давайте возьмём эту задачу и реализуем её на Python.

RussianEnglishDictionary = {'яблоко': 'apple', 'идти': 'to come', 'язык':'language'}

Этих слов можно добавлять бесконечно много. А теперь как можно найти перевод слова по значению? Предлагаю это реализовать.

RussianEnglishDictionary = {'яблоко': 'apple', 'идти': 'to come', 'язык':'language'} print(RussianEnglishDictionary['яблоко']) # apple

Думаю, ассоциация может помочь понять и разобраться лучше в понимании о словарях.

Какие характеристики выделил М.Лутц по отношению к словарям?

  • Они поддерживают доступ по ключу, а не смещению. Я впервые увидел что словари могут также называть ассоциативными массивами или хешами
  • Они являются неупорядоченными коллекциями произвольных объектов. Элементы в словаре не поддерживают определённый порядок
  • Они имеют переменную длину, разнородны т допускают глубокое вхождение. (аналогию со списками не видите?)
  • Они относятся к категории изменяемые отображения. Словари в Python называют единственным инструментом, которым свойственно отображение. Их разрешено менять на месте, выполняя присваивания по индексам, они не поддерживают операции над последовательностями, которые работают на строках и списках
  • Они представляют таблицы ссылок на объекты. Словари - неупорядоченные таблицы ссылок на объекты.

Как иначе можно реализовывать словари?

1) Пример. Через словарь в словаре

PersonalDataDict = {'person' : {'firstname': 'Misha', 'lastname': 'Ivashkin'}} #{'person': {'firstname': 'Misha', 'lastname': 'Ivashkin'}}

2) Через вывод служебного слова dict()

PersonalDataDict = dict(firstname = 'Misha', lastname = 'Ivashkin') # {'firstname': 'Misha', 'lastname': 'Ivashkin'}

3) Через служебное слово zip()

keysList = ['firsname', 'lastname'] valuesList = ['Misha', 'Ivashkin'] PersonalData = dict(zip(keysList, valuesList)) # {'firsname': 'Misha', 'lastname': 'Ivashkin'}

Все методы по работе со словарями можно получить по следующей ссылке.

Как работать со словарями?

1 Пример. Изменение словарей на месте.

Допустим, у нас есть словарь, отображающий количество овощей и фруктов в корзине.

ItemsDict = {'potatoes': 2, 'kiwi': 3, 'tomatoes': 4}

Давайте поменяем, количество помидор на список из 3 значений (допустим у нас их несколько видов:

ItemsDict['tomatoes'] = [1,1,2] print(ItemsDict) # {'potatoes': 2, 'kiwi': 3, 'tomatoes': [1, 1, 2]}

Таким образом получается, что в словарь можно вставлять список.

2 Пример. авайте удалим картофель из словаря ( например, мы его написали ошибочно)

del ItemsDict['potatoes'] print(ItemsDict) # {'kiwi': 3, 'tomatoes': [1, 1, 2]}

3 Пример. А что, если я захочу добавить морковь? Да проще простого!

ItemsDict['carrots'] = 6 print(ItemsDict) # {'potatoes': 2, 'kiwi': 3, 'tomatoes': [1, 1, 2], 'carrots': 6}

А вот с методами предлагаю попробовать поиграться самостоятельно. Тем более большая их часть повторяет списки с некоторыми дополнениями вроде dict.get(), dict.values(), dict.keys()

Немного про сложные случаи

В ряде случаев словари работают точно также как и списки. Они также могут поддерживать встроенные map() и list comprehention

Приведу сложные сложных случаев на примере из следующего отображения

DateOfBirth = { 'Misha': 1996, 'Masha' : 2000, 'Oleg' : 2002 }

1 Пример. Отображение списка из значений

print(DateOfBirth.items()) # dict_items([('Misha', 1996), ('Masha', 2000), ('Oleg', 2002)])

2 Пример. ListComprehention

K = 'Oleg' V = DateOfBirth[K] print([key for key in DateOfBirth.keys() if DateOfBirth[key]==V]) #Oleg для ключа print([key for (key, value) in DateOfBirth.items() if value==V]) # Oleg аналогичный вывод

В последнем случае применение цикла выглядит немного интересней. В первом случае мы используем только ключ в цикле, а во втором и ключ и значение. Когда мы их используем совместно, необходимо объединить их скобками. Лично я не привык писать цикл для словарей в одну строчку, но считаю такой подход очень полезным навыком.

Есть какие-то замечания, когда мы используем словари?

Конечно есть! Лутц, например, выделяет три основных замечания.

1) В словарях не работают операции с последовательностями вроде нарезания и конкатинации. Если я их захочу использовать Python выведет ошибку. (Попробуйте сами)

2) Присваивание по индексам добавляет элементы. Помните пример с морковкой?

3) Ключи не обязаны быть строками. Это да, они могут являться и строками и числами (это как минимум), а как максимум не знаю даже что сказать.

Пример:

Number = {} Number[99] = 'ninety nine' print(Number) # {99: 'ninety nine'}

Любопытный пример использования словаря, который я вычитал у Лутца

Оказывается в качестве ключа могут выступать как единичные значения, так и множественные. И тут в голову приходит нахождение точки по заданным координатам. Смотрите какая красота. Не уверен конечно, что данный шаблон часто применяется, но это выглядит довольно-любопытно по крайней мере.

Point = {} Point[(1,2,3)]='A' print(Point) # {(1, 2, 3): 'A'} Координаты 1,2,3 имеет точка А

Вы что-то говорили про существование вложенных словарей. Можно подробней на них остановиться?

Даже нужно. Поскольку вложенные словари служат даже примером вывода данных в формате JSON (о нём поговорим в другой статье). Поэтому, чтобы понять как работает словарь Лутц предлагает его создать.

Предлагаю немного поменять его пример на наш.

MyData = {} MyData['name'] = 'Misha' MyData['age'] = 26.3 MyData['skills'] = ['entrepreneur', 'young scientist'] MyData['home'] = {'country': 'Russia', 'city': 'Yekaterinburg'} print(MyData) #{'name': 'Misha', 'age': 26.3, 'skills': ['entrepreneur', 'young scientist'], 'home': {'country': 'Russia', 'city': 'Yekaterinburg'}}

Словарь может сказать обо мне (да и о вас всё). Кстати такой формат словаря может вполне соответствовать боевым данным.

Вы что-то писали, что существует очень много способов создания словаря. А какой из них удобный?

Каждый способ удобен по-своему. Давайте через примеры пойдём.

Пример 1

{'name': 'Misha', 'lastname': 'Ivashkin'}

Удобен, когда мы можем составить словарь заранее

Пример 2.

MyData = {} MyData['name'] ='Misha' MyData['lastname'] = 'Ivashkin'

Применяется, когда словарь создаётся на лету. Как правило такой формат объявляется перед применением цикла for, ну или как в моём случае

Пример 3.

dict(name = 'Misha', lastname = 'Ivashkin')

Основное требование третьего примера - необходимость, чтобы все ключи являлись строками

Пример 4.

dict([('firsname', 'lastname'), ('Misha', 'Ivashkin')])

Используется когда необходимо накапливать ключи и значения

Лично я часто использую шаблоны первого и второго примера

Это всё интересно, конечно. Но где-то я уже подобный символ встречал у вас в статьях. Можете напомнить где?

Конечно могу, словарь очень похож на множества. Но это не совсем так. Например ключи (keys) подобны множествам и поддерживают операции над множествами (пересечения и объединение). А метод (values) не подобны множествам. Однако items() (совместная пара ключ-значение) являются подобными, если пары (ключ/значения) уникальны и хешируемые.

Трудно конечно в этом разобраться, читая текст. Давайте лучше на примерах.

Пример.

Давайте поиграемся вот с этими данными

MyDict = {'FirstValue': 1, 'SecondValue': 2, 'ThirdValue': 3} MyKey = MyDict.keys() MyValue = MyDict.values() #dict_keys(['FirstValue', 'SecondValue', 'ThirdValue']) dict_values([1, 2, 3]) MyKey | {'FourthValue': 4} # множества поддерживают логический оператор "или" MyValue | {'FourthValue': 4} # А вот тут ошибка типа MyDict.keys() | MyDict.keys() # {'SecondValue', 'FirstValue', 'ThirdValue'} MyDict.keys() & {'FirstValue'} # {'FirstValue'} MyDict.items() | MyDict.keys() # Объединение items() и keys()

В общем я не знаю, как это использовать на практике, но тот факт, что словари поддерживают работу со множествами вызывал у меня сильный интерес

Фуф. Я устал. Пойду кофе пить. Спасибо за внимание!

Списки и словари по Марку Лутцу
11
2 комментария

List Comprehention ???
А чем вам не угодило название "генераторы списков", также есть вариант в круглых скобках - "генераторы выражений".

1

Спасибо за замечание. Да, Вы правы, видимо просто не нашёл эквивалентный русский перевод