Простые примеры работы со структурами данных в Python

Хола! Скажу так, детально разбирать и переписывать документацию по Python я не буду, однако ряд первых статей будут посвящены основам. И первое, на что надо обратить свое внимание структуры или типы данных. Изучать программирование вообще стоит именно со структур данных, ведь именно с данными нам и придется работать постоянно.

В Python реализованы несколько структур данных, ниже некоторые из них:

  1. целые числа (int) *
  2. вещественные числа (float) *
  3. строки (str) *
  4. кортеж (tuple) *
  5. логический тип данных (True, False) *
  6. списки (list)
  7. словари (dict)
  8. frozenset * – неизменяемая версия словаря
  9. множество (set)

Звездочкой помечены неизменяемые типы данных.

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

Неизменяемый тип данных

Логично предположить, что такие типы данных мы не можем изменить, но как тогда с ними оперировать? Для примера буду использовать целы числа, они являются неизменяемым типом данных. Разберем, что произойдет в следующем коде:

a = 10
b = 15
a = a + b

и вспомним как Python хранит данные. Переменные a и b ссылаются на объекты в памяти созданные для чисел 10 и 15, в третьей строчке переменная a ссылается на новый объект в памяти, который является результатом операции сложения a и b. Таким образом мы не изменили объект 10 в памяти, мы создали третий объект и сослались на него.

Python хитро использует такие данные, ведь если объект неизменяемый, но мы ссылаемся на него в коде несколько раз, то зачем каждый раз создавать этот объект? Объект будет создан единожды, а все переменные с таким значением будут ссылаться на один и тот же объект. Наглядности прибавит нам built-in функция id() которая возвращает нам идентификатор объекта в оперативной памяти. Разберем код ниже:

a = 10
b = 10
c = 10

print(id(a), id(b), id(c), sep='\n')

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

Изменяемый тип данных

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

a = [1,2,3,4,'Hello']
b = [1,2,3,4,'Hello']
c = [1,2,3,4,'Hello']

print(id(a), id(b), id(c), sep='\n')

Если все, что мы сказали выше верно, а оно определенно верно, то мы сейчас создадим магию (нет). Числа неизменяемый тип данных, можно сказать «переиспользуемые» объекты в памяти. Создав три переменные с тремя разными числами и указав их значения в изменяемом типе список, мы получим, что элементы списка ссылаются на ранее созданный объект. Для наглядности выполним код:

x = 1
y = 2
z = 3

a = [1,2,3]
b = [1,2,3]
c = [1,2,3]

print(id(x), id(y), id(z), sep='\n')
print(id(a[0]), id(b[1]), id(c[2]), sep='\n')

Какой мы сделаем вывод? Python не плодит неизменяемые объекты в памяти, если они одинакового значения, он создает один такой объект, а дальше просто ссылается на него. Список также не является просто объектом со значениями, он является объектом, элементы которого могут являться ссылками на другие объекты. Это, кстати, и есть объяснение фразы, которую вы часто будете слышать, что все в Python является объектами и отношениями между ними.

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

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

mylist = [1,2,3,4,4,5,5,6,6,7,1,2,3,4,5,6] # создали список с числами

result = [] # сюда мы запишем результат

for i in mylist: # в цикле итерируем каждый элемент поочередно
    if i not in result: # если этого элемента нет в списке result
        result.append(i) # добавим его туда

Код примитивный, но рабочий, у нас есть список со значениями и список, в который мы записываем элемент, если его там нет. Возвращаясь к тому, что Python не плодит объекты в памяти, это отлично реализовано в случае с логическим типом данных (False / True), в строчке условия if i not in result мы получим либо True, либо False, эти два значения есть как объекты в памяти и сотни условий будут ссылаться только на эти два объекта в памяти в зависимости от результата выполнения условия, а не создавать каждый раз новый объект для частного случая.

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

mylist = [1,2,3,4,4,5,5,6,6,7,1,2,3,4,5,6]

for i in mylist: # в цикле итерируем каждый элемент поочередно
    print(i **2) # выводим результат. **2 означает, что мы возводим число в степень.

Это простенькие, но рабочие программы, которые в целом решают какую-то задачу и реализация тут не самая лаконичная. Напишем что-то, что работает со словарем. Словарь интересен тем, что содержит ключ и значение. Пример словаря:

 mydict = {
    'Name': 'value',
    'Age': 21,
    'City': 'Moscow',
}

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

mydict = {
    'Name': 'value',
    'Age': 21,
    'City': 'Moscow',
    'Dict': {
        'Phone': 8800777555,
        'Zip': 123546
    }
}

print(mydict['Dict']['Zip'])

Обращение к вложенному словарю в данном случае выглядит так словарь[ключ][ключ_вложенного_словаря]. Выполните код выше и результатом будет: 123456. Записать в словарь ключ со значением можно при помощи конструкции словарь[имя_нового_ключа] = [значение]. Пример:

mydict = {
    'Name': 'Tim',
    'Age': 21,
    'City': 'Moscow',
    'Dict': {
        'Phone': 8800777555,
        'Zip': 123546
    }
}

mydict['Surname'] = ['Ivanov']

print(mydict['Surname'])

Напишем программу, которая может выводить все значения по всем ключам и проверять, если значение ключа словарь, то выводить значения для его ключей:

mydict = {
    'Name': 'Tim',
    'Age': 21,
    'City': 'Moscow',
    'Dict': {
        'Phone': 8800777555,
        'Zip': 123546,
    }
}

mydict['Surname'] = ['Ivanov']

for i in mydict: # начнем итерировать элементы словаря (ключи)
    if type(mydict[i]) != dict: # если тип значения ключа не словарь
        print(mydict[i])# выводим значение
    else: # иначе проходим по ключам вложенного словаря
        for j in mydict[i]:
            print(mydict[i][j]) # и выводим уже значения всех его ключей.

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

Как видно в примерах кода, я обращаюсь к элементам списка или словаря следующим образом dict[i]. Это обращение по индексу к элементу списка, словаря, строки и т.д. Нумерация индекса начинается с 0, для словарей и списков со строками, мы увидим, данные сохраняют свой порядок, но вот с таким типом данных как множество дело обстоит немного иначе. Дело в том, что элементы множества неупорядоченные и при каждой новой инициализации элементы в нем будут смешиваться, наглядно можно посмотреть, выполнив этот код несколько раз и сравнить каждый раз результат вывода:

simple = set('Hello, world!')
print(simple)

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