Кроме того, так как имена полей являются независимыми переменными, между записью в виде списка и именами полей отсутствует обратная связь. Имея одну только запись в виде списка, например, нельзя реализовать форматированный вывод значений полей с их именами. В случае с предыдущей записью без дополнительных ухищрений невозможно получить имя AGE из значения 42: вызов bob.index(42) вернет 1, значение переменной AGE, но не само имя AGE.
Можно было бы попробовать представлять записи в виде списков кортежей, где кортежи хранят не только значения полей, но их имена. Но еще лучше было бы использовать списки списков, что позволило бы изменять поля (кортежи относятся к категории неизменяемых объектов). Ниже демонстрируется воплощение этой идеи на примере простых записей:
>>> bob = [['name', ‘Bob Smith'], ['age', 42], ['pay', 10000]]
>>> sue = [['name', ‘Sue Jones'], ['age', 45], ['pay', 20000]]
>>> people = [bob, sue]
Однако на самом деле этот прием не решает проблему, потому что для извлечения полей все равно необходимо использовать числовые индексы:
>>> for person in people:
print(person[0][1], person[2][1]) # имя, оклад
Bob Smith 10000 Sue Jones 20000
>>> [person[0][1] for person in people] # выборка имен [‘Bob Smith’, ‘Sue Jones’]
>>> for person in people:
print(person[0][1].split()[-1]) # получить фамилию person[2][1] *= 1.10 # повысить оклад на 10%
Smith
Jones
>>> for person in people: print(person[2])
[‘pay’, 11000.0]
[‘pay’, 22000.0]
Все, чего мы добились, - добавили еще один уровень индексирования. Для достижения желаемого мы могли бы просматривать имена полей в цикле, отыскивая необходимые (в следующем цикле используется операция присваивания кортежа для распаковывания пар имя/значение):
>>> for person in people:
for (name, value) in person:
if name == ‘name': print(value) # поиск требуемого поля
Bob Smith Sue Jones
Еще лучше было бы реализовать функцию, выполняющую всю работу за нас:
>>> def field(record, label):
for (fname, fvalue) in record:
if fname == labeclass="underline" # поиск поля по имени
return fvalue
>>> field(bob, ‘name')
‘Bob Smith’
>>> field(sue, ‘pay')
22000.0
>>> for rec in people: # вывести возраст всех людей
print(field(rec, ‘age')) # в базе данных
42
45
Если двигаться дальше по этому пути, в конечном итоге можно получить набор функций, осуществляющих интерфейс к записям, отображающих имена полей в их значения. Однако если прежде вам приходилось программировать на языке Python, вы наверняка знаете, что существует более простой способ реализации такого рода ассоциаций, и вы уже наверняка догадались, в какую сторону мы направимся в следующем разделе.
Словари
Реализация записей на основе списков, как было показано в предыдущем разделе, вполне работоспособна, хотя и за счет некоторой потери производительности из-за необходимости выполнять поиск полей по именам (если вас волнуют потери, измеряемые миллисекундами). Однако если вы уже имеете некоторое знакомство с языком Python, вы должны знать, что существуют более эффективные и более удобные способы связывания имен полей с их значениями. Встроенные объекты словарей выглядят естественно:
>>> bob = {‘name': ‘Bob Smith', ‘age': 42, ‘pay': 30000, ‘job': ‘dev'}
>>> sue = {‘name': ‘Sue Jones', ‘age': 45, ‘pay': 40000, ‘job': ‘hdw'}
Теперь bob и sue - это объекты, автоматически отображающие имена полей в их значения, и их использование делает программный код более простым и понятным. Нам не требуется запоминать, что означают числовые индексы, и мы даем интерпретатору возможность использовать его высокоэффективный алгоритм индексации словарей, чтобы отыскивать значения полей, ассоциированные с их именами:
>>> bob[‘name'], sue[‘pay'] # в отличие от bob[0], sue[2]
(‘Bob Smith’, 40000)
>>> bob[‘name'].split()[-1]
‘Smith’
>>> sue[‘pay'] *= 1.10
>>> sue[‘pay']
44000.0
Поскольку теперь при обращении к полям используются символические имена, программный код выглядит более осмысленным для всех, кто будет читать его (включая и вас).
Другие способы создания словарей
Словари являются настолько удобными объектами при программировании на языке Python, что было предусмотрено еще несколько способов их создания, отличающихся от традиционного синтаксиса литералов, продемонстрированного выше, - например, вызовом конструктора с именованными аргументами, при этом все ключи будут строками:
>>> 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’}
>>> sue
{‘pay’: 40000, ‘job’: ‘hdw’, ‘age’: 45, ‘name’: ‘Sue Jones’}
заполнением словаря поле за полем (напомню, что для ключей словаря не предусматривается какой-то определенный порядок следования):