Выбрать главу

my_list[0] = 4

print my_list # [4, 2, 3] <- тот же список, измененный.

# Целые числа изменять нельзя

x = 6

x = x + 1 # Новое значение x занимает другое место в памяти.

• Изменяемые типы. Позволяют изменять содержимое объекта на месте. Примерами могут стать списки и словари, которые имеют изменяющие методы вроде list.append() или dict.pop() и могут быть модифицированы на месте.

• Неизменяемые типы. Не предоставляют методов для изменения их содержимого. Например, переменная х со значением 6 не имеет метода для инкремента. Для того чтобы вычислить значение выражения х + 1, нужно создать другую целочисленную переменную и дать ей имя.

Одно из последствий такого поведения — объекты изменяемых типов не могут быть использованы как ключи для словаря, ведь если их значение изменится, то изменится и его хэш (словари используют хэширование[45] для хранения ключей). Неизменяемым эквивалентом списка является кортеж. Он создается добавлением круглых скобок, например (1, 2). Кортеж нельзя изменить на месте, поэтому его можно использовать как ключ словаря.

Правильное применение изменяемых типов для объектов, которые по задумке должны изменяться (например, my_list = [1, 2, 3]), и неизменяемых типов для объектов, которые по задумке должны иметь фиксированное значение (например, islington_phone = ("220", "7946", "0347")), поможет другим разработчикам понять код.

В Python строки неизменяемы и это может удивить новичков. Попытка изменить строку вызовет ошибку:

>>> s = "I'm not mutable"

>>> s[1:7] = " am"

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: 'str' object does not support item assignment

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

Таблица 4.3. Способы конкатенации строки
Плохой Хороший Лучший
>>> s = "" >>> s = [] >>> r = (97, 98, 99)
>>> for c in (97, 98, 98): >>> for c in (97, 98, 99): >>> s = [unichr(c) for
… ····s += unichr(c) … ····s.append(unichr(c)) ····c in r]
>>> print("".join(s))
>>> print(s) >>> print("".join(s)) abc
abc abc  

На главной странице Python (https://www.python.org/doc/essays/list2str/) вы можете найти обсуждение подобной оптимизации.

Наконец, если количество элементов конкатенации известно, добавить строку будет проще (и очевиднее), чем создавать список элементов только для того, чтобы вызвать функцию "".join().

Все следующие варианты форматирования для определения переменной cheese делают одно и то же[46]:

>>> adj = "Red"

>>> noun = "Leicester"

>>>

>>> cheese = "%s %s" % (adj, noun) # Этот стиль устарел (PEP 3101)

>>> cheese = "{} {}".format(adj, noun) # Возможно начиная с Python 3.1

>>> cheese = "{0} {1}".format(adj, noun) # Числа можно использовать повторно

>>> cheese = "{adj} {noun}".format(adj=adj, noun=noun) # Этот стиль — лучший

>>> print(cheese)

Red Leicester

Зависимости, получаемые от третьей стороны

Пакет, который использует зависимости, получаемые от третьей стороны, содержит внешние зависимости (сторонние библиотеки) внутри своего исходного кода, зачастую внутри каталога с именем vendor или packages. По адресу http://bit.ly/on-vendorizing вы можете прочесть весьма полезную статью, в которой перечисляются основные причины, почему владелец пакета может воспользоваться зависимостями третьей стороны (в основном для того, чтобы избежать проблем с совместимостью), а также рассматриваются альтернативные подходы.

вернуться

45

Пример простого алгоритма хэширования — преобразование байтов объекта в целое число и взятие его суммы по какому-нибудь модулю. memcached (http://www.memcached.org/) распределяет ключи между несколькими компьютерами именно так.

вернуться

46

Должны признать: хотя в PEP 3101 (https://www.python.org/dev/peps/pep-3101/) форматирование с использованием знака % (%s, %d, %f) считается устаревшим, большинство разработчиков старой школы все еще используют его. В PEP 460 (https://www.python.org/dev/peps/pep-0460/) был представлен такой же метод форматирования байтов или объектов bytearray.