software
writing
>> bob2[‘job'][-1] # последняя должность Боба
‘writing’
>>> bob2[‘job'].append(‘janitor') # Боб получает новую должность >>> bob2
{‘job’: [‘software’, ‘writing’, ‘janitor’], ‘pay’: (40000, 50000), ‘age’: 42, ‘name’: {‘last’: ‘Smith’, ‘first’: ‘Bob’}}
В расширении вложенного списка с помощью метода append нет ничего необычного, потому что в действительности он является независимым объектом. Такие вложенные конструкции могут пригодиться в более сложных приложениях. Однако, чтобы не усложнять примеры, мы сохраним прежнюю, плоскую структуру записей.
Словари словарей
И еще один поворот в реализации нашей базы данных с информацией о людях: мы можем расширить область применения словарей, задействовав еще один словарь для представления самой базы данных. То есть мы можем создать словарь словарей - внешний словарь будет играть роль базы данных, а вложенные словари - роль записей. В отличие от простого списка записей, база данных, представленная в виде словаря, позволит нам сохранять и извлекать записи с помощью символических ключей:
>>> bob = dict(name='Bob Smith', age=42, pay=30000, job='dev')
>>> sue = dict(name='Sue Jones', age=45, pay=40000, job='hdw')
>>> bob
{‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}
>>> db = {}
>>> db[‘bob'] = bob # ссылки на словари в словаре
>>> db[‘sue'] = sue
>>>
>>> db[‘bob'][‘name'] # извлечь имя Боба
‘Bob Smith’
>>> db[‘sue'][‘pay'] = 50000 # изменить оклад Сью
>>> db[‘sue'][‘pay'] # извлечь оклад Сью
50000
Обратите внимание, что такая организация позволяет нам обращаться к записям непосредственно, без необходимости выполнять поиск в цикле - мы получаем непосредственный доступ к записи с информацией о Бобе за счет использования ключа bob. Это действительно словарь словарей, хотя это и не заметно, если не вывести всю базу данных сразу (для подобных целей удобно использовать модуль pprint форматированного вывода):
>>> db
{‘bob’: {‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}, ‘sue’: {‘pay’: 50000, ‘job’: ‘hdw’, ‘age’: 45, ‘name’: ‘Sue Jones’}}
>>> import pprint >>> pprint.pprint(db)
{‘bob’: {‘age’: 42, ‘job’: ‘dev’, ‘name’: ‘Bob Smith’, ‘pay’: 30000},
‘sue’: {‘age’: 45, ‘job’: ‘hdw’, ‘name’: ‘Sue Jones’, ‘pay’: 50000}}
Если же возникнет необходимость последовательно обойти все записи в базе данных, можно воспользоваться итераторами словарей. В последних версиях Python реализован итератор словаря, который на каждой итерации в цикле for воспроизводит по одному ключу (для совместимости с более ранними версиями в циклах for можно также вместо простого имени db использовать явный вызов метода db. keys, но, так как в Python 3 метод keys возвращает генератор, конечный результат будет тот же самый):
>>> for key in db:
print(key, ‘=>', db[key][‘name'])
bob => Bob Smith sue => Sue Jones
>>> for key in db:
print(key, ‘=>', db[key][‘pay'])
bob => 30000 sue => 50000
В процессе обхода доступ к отдельным записям можно получать с использованием операции индексирования по ключу:
>>> for key in db:
print(db[key][‘name'].split()[-1]) db[key][‘pay'] *= 1.10
Smith
Jones
или напрямую, организовав обход значений словаря:
>>> for record in db.values(): print(record[‘pay'])
33000.0
55000.0
>>> x = [db[key][‘name'] for key in db]
>>> x
[‘Bob Smith’, ‘Sue Jones’]
>>> x = [rec[‘name'] for rec in db.values()]
>>> x
[‘Bob Smith’, ‘Sue Jones’]
А чтобы добавить новую запись, достаточно просто выполнить операцию присваивания по новому ключу. В конце концов - это всего лишь словарь:
>>> db[‘tom'] = dict(name='Tom', age=50, job=None, pay=0)
>>>
>>> db[‘tom']
{‘pay’: 0, ‘job’: None, ‘age’: 50, ‘name’: ‘Tom’}
>>> db[‘tom'][‘name']
‘Tom’
>>> list(db.keys())
[‘bob’, ‘sue’, ‘tom’]
>>> len(db)
3
>>> [rec[‘age'] for rec in db.values()]
[42, 45, 50]
>>> [rec[‘name'] for rec in db.values() if rec[‘age'] >= 45] # SQL-подобный [‘Sue Jones’, ‘Tom’] # запрос
Наша база данных по-прежнему является объектом, хранящимся в оперативной памяти. Но, как оказывается, такой формат словаря словарей в точности соответствует формату, который используется системой сохранения объектов в файлах, - модулем shelve (с точки зрения грамматики английского языка этот модуль должен был бы называться shelf, но в Python термин shelve, обозначающий сохранение объектов, одновременно служит и названием соответствующего ему модуля). О том, как это делается, вы узнаете в следующем разделе.
Шаг 2: сохранение записей на длительное время
К настоящему моменту мы остановились на представлении нашей базы данных в виде словаря и попутно рассмотрели некоторые способы реализации структур данных в языке Python. Однако, как уже упоминалось выше, объекты, с которыми мы имели дело до сих пор, - временные объекты; они располагаются в оперативной памяти и исчезают бесследно после завершения работы интерпретатора Python или программы, создавшей их. Чтобы обеспечить долговременное хранение базы данных, ее необходимо сохранить в каком-нибудь файле.