Многие примеры кода, показанные в первых главах этой книги, демонстрируют, что порядок ключей в словаре нельзя предсказать: вы можете добавить в определенном порядке ключи a, b и c, но функция keys() вернет результат "c, a, b". Рассмотрим модифицированный пример из главы 1:
>>> quotes = {
…·····'Moe': 'A wise guy, huh?',
…·····'Larry': 'Ow!',
…·····'Curly': 'Nyuk nyuk!',
…·····}
>>> for stooge in quotes:
…··print(stooge)
…
Larry
Curly
Moe
Словарь OrderedDict() запоминает порядок, в котором добавлялись ключи, и возвращает их в том же порядке с помощью итератора. Попробуем создать OrderedDict из последовательности кортежей вида «ключ — значение»:
>>> from collections import OrderedDict
>>> quotes = OrderedDict([
…·····('Moe', 'A wise guy, huh?'),
…·····('Larry', 'Ow!'),
…·····('Curly', 'Nyuk nyuk!'),
…·····])
>>>
>>> for stooge in quotes:
…·····print(stooge)
…
Moe
Larry
Curly
Стек + очередь == deque
deque (произносится как «дэк») — это двухсторонняя очередь, которая имеет возможности стека и очереди. Она полезна, когда вы хотите добавить и удалить элементы с любого конца последовательности. В следующем примере мы будем двигаться с обоих концов слова к его середине, чтобы увидеть, является ли оно палиндромом. Функция popleft() удаляет крайний слева элемент deque и возвращает его, функция pop() удаляет крайний справа элемент и возвращает его. Вместе они двигаются с концов слова к его середине. Работа будет продолжаться до тех пор, пока крайние символы совпадают и пока не будет достигнута середина:
>>> def palindrome(word):
…·····from collections import deque
…·····dq = deque(word)
…·····while len(dq) > 1:
…········if dq.popleft()!= dq.pop():
…············return False
…·····return True
…
…
>>> palindrome('a')
True
>>> palindrome('racecar')
True
>>> palindrome('')
True
>>> palindrome('radar')
True
>>> palindrome('halibut')
False
Я воспользовался этим примером, чтобы было проще проиллюстрировать работу deque. Если вы действительно хотите создать программу, которая определяет палиндромы, гораздо проще было бы сравнивать строку с ее копией, вывернутой наизнанку. В Python строковой функции reverse() не существует, но можно обратить строку с помощью разбиения, как показано здесь:
>>> def another_palindrome(word):
…·····return word == word[::-1]
…
>>> another_palindrome('radar')
True
>>> another_palindrome('halibut')
False
Итерируем по структурам кода с помощью itertools
itertools содержит особые функции итератора. Каждая из них возвращает один элемент при каждом вызове из цикла for … in и запоминает свое состояние между вызовами.
Функция chain() проходит по своим аргументам, как если бы они были единым итерабельным объектом:
>>> import itertools
>>> for item in itertools.chain([1, 2], ['a', 'b']):
…·····print(item)
…
1
2
a
b
Функция cycle() является бесконечным итератором, проходящим в цикле по своим аргументам:
>>> import itertools
>>> for item in itertools.cycle([1, 2]):
…·····print(item)
…
1
2
1
2
.
.
.
…и т. д.
Функция accumulate() подсчитывает накопленные значения. По умолчанию она высчитывает сумму:
>>> import itertools
>>> for item in itertools.accumulate([1, 2, 3, 4]):
…·····print(item)
…
1
3
6
10
В качестве второго аргумента функции accumulate() вы можете передать функцию, и она будет использована вместо сложения. Функция должна принимать два аргумента и возвращать одно значение. В этом примере высчитывается произведение:
>>> import itertools
>>> def multiply(a, b):
…·····return a * b
…
>>> for item in itertools.accumulate([1, 2, 3, 4], multiply):
…·····print(item)
…
1
2
6
24
Модуль itertools имеет еще много функций, он известен благодаря определенным комбинациям и преобразованиям, которые могут сохранить кучу времени, если в них появится необходимость.