понедельник, 7 декабря 2015 г.

Изменяемость и неизменяемость объектов, ссылки, списки и словари

Изменяемость и неизменяемость(mutable and immutable)



Рассмотрим понятия изменяемости(Mutable) и неизменяемости(immutable) встроенных типов данных в python. Скажем сразу, что числа, строки и кортежи - это неизменяемые объекты, а списки и словари - изменяемые.
Что это значит? Мы никогда не можем изменить оригинал содержимого неизменяемого объекта Т.Е. Мы ничем не сможем изменить строку, число или кортеж, после того как мы создали объект одного из этих типов. Объекты списков и словарей, мы можем изменять, взаимодействуя с оригиналом содержимого объекта. Как это увидеть? Давайте вспомним методы раоты со строками из темы (2). Когда мы разбивали строку или делали замену одной части строки на чтолибо, оригинал строки никогда не изменялся. Python возвращал нам измененную строку при replace() или список элементов при split(), но объект строки никогда не изменялся. Давайте посмотрим на это в действии.

>>> a = "I shocked by the splendor of Python"

>>> a

'I shocked by the splendor of Python'

>>> a.split(" ")

['I', 'shocked', 'by', 'the', 'splendor', 'of', 'Python']

>>> print a.replace(" ", "\n")

I

shocked

by

the

splendor

of

Python

>>> a

'I shocked by the splendor of Python'

>>>


Как мы видем, мы "поиздевались" над строкой, но оригинальная строка, на которую ссылается переменная "a", осталась неизменной. Чтобы сохранить изменение, которое мы применяем к строке, нам нужно физически переопределить его для переменной "a" или присвоить измененную строку новой переменной.


Более подробно изменяемость списков и словарей, вы сможете наблюдать далее в этой теме, но если говорить в кратце, все изменения которые мы предположительно можем делать над списком или словарем, приведет к изменению оригинала содержимого объекта. Пронаблюдать за этим мы можем на простом примере.

>>> a = ["Buratino", "Pinokio"]

>>> a

['Buratino', 'Pinokio']

>>> a[0]

'Buratino'

>>> a[1]

'Pinokio'

>>> a[1] = "Malvina"

>>> a

['Buratino', 'Malvina']

>>> a[1]

'Malvina'

>>>


Мы создали список и обратившись к второму элементу списка по индексу, просто изменили его содержимое, что привело к изменению оригинала списка.


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

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


Переменные как ссылки



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

>>> a

['Grey', 'Red', 'Pink', 'Magenta', 'Blue', 'Green', 'Red']

>>> b = a # Переменная b, ссылается на тотже объект, что и a

>>> a

['Grey', 'Red', 'Pink', 'Magenta', 'Blue', 'Green', 'Red']

>>> b

['Grey', 'Red', 'Pink', 'Magenta', 'Blue', 'Green', 'Red']

>>> a[0] = "Cat"

>>> a[2] = "Dog"

>>> a

['Cat', 'Red', 'Dog', 'Magenta', 'Blue', 'Green', 'Red']

>>> b

['Cat', 'Red', 'Dog', 'Magenta', 'Blue', 'Green', 'Red']

>>> b[0] = "Mumitrol"

>>> b[1] = "trololo"

>>> a

['Mumitrol', 'trololo', 'Dog', 'Magenta', 'Blue', 'Green', 'Red']

>>> b

['Mumitrol', 'trololo', 'Dog', 'Magenta', 'Blue', 'Green', 'Red']

>>>


Как видим, если мы присваиваем какой-то переменной переменную, которая ссылается на какойлибо объект, практически мы присваиваем этой переменной ссылку на объект. Как создать независимые копии объектов при необходимости, ббудет рассмотрено далее в этой теме.


Списки и методы списков



Устроим быструю экскурсию в набор методов для взаимодействия со списками. На первом месте стоит метод append(), который позволяет добавлять элементы в конец списка. Рассмотрим это на примере:

>>> a = [] # Объявили пустой список

>>> a.append("Red")

>>> a

['Red']

>>> a.append("Green")

>>> a.append("Blue")

>>> a

['Red', 'Green', 'Blue']

>>> a[0]

'Red'

>>> a[1]

'Green'

>>> a[2]

'Blue'

>>>


На этом примере, мы видем не только работу метода append(), а и явную изменяемость оригинала списка. Создали пустым, а в результате последовательно добавили туда 3 элемента.

Еще один метод расширения списка - это extend(). Он позволяет вставлять в конец списка не один элемент, а список. Какбы продолжает список другим списком. Как много слов "список" на квадратный сантиметр текста!

>>> a

['Red', 'Green', 'Blue']

>>> a.extend(["Grey", "Black", "White"])

>>> a

['Red', 'Green', 'Blue', 'Grey', 'Black', 'White']

>>>


Еще один метод для расширения списка - insert(). Он позволяет вставить элемент на необходимое место в списке, указывая индекс, на который вы хотите поместить этот элемент, причем правая часть списка сместиться на один индекс в большую сторону.

>>> a

['Red', 'Green', 'Blue', 'Grey', 'Black', 'White']

>>> a[0]

'Red'

>>> a[1]

'Green'

>>> a.insert(1, "Magenta")

>>> a

['Red', 'Magenta', 'Green', 'Blue', 'Grey', 'Black', 'White']

>>> a[0]

'Red'

>>> a[1]

'Magenta'

>>> a[2]

'Green'

>>> a[3]

'Blue'

>>>


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

Метод remove(), удаляет первый встреченный в списке элемент, с указанным содержимым.

>>> a

['Red', 'Magenta', 'Green', 'Blue', 'Grey', 'Black', 'White']

>>> a.remove("Black")

>>> a.remove("Blue")

>>> a

['Red', 'Magenta', 'Green', 'Grey', 'White']

>>>


Метод pop(), позволяет удалять элемент списка по его индексу или, если индекс не указан, удаляет последний элемент списка. При удалении, метод возвращает удаляемый элемент.

>>> a

['Red', 'Magenta', 'Green', 'Grey', 'White']

>>> a[2]

'Green'

>>> a.pop(2)

'Green'

>>> a

['Red', 'Magenta', 'Grey', 'White']

>>> a[2]

'Grey'

>>> a

['Red', 'Magenta', 'Grey', 'White']

>>> a.pop()

'White'

>>> a

['Red', 'Magenta', 'Grey']

>>>


Метод index(), возвращает индекс первого встреченного элемента по его содержимому. Также метод index(), содержит в себе 2 опциональных аргумента: индекс для начала поиска и индекс конца поиска, а-ля срез.

>>> a = ["Red", "Green", "Blue", "Magenta", "Pink", "Red", "Grey"]

>>> a

['Red', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>> a.index("Magenta")

3

>>> a[3]

'Magenta'

>>> a.index("Red")

0

>>> a[0]

'Red'

>>> a.index("Red", 2) # Ищем элемент Red начиная с элемента под индексом 2

5

>>> a[5]

'Red'

>>> a.index("Red", 1, 4) # Ищем элемент Red между индексами 1 и 4

Traceback (most recent call last):

  File "", line 1, in

ValueError: 'Red' is not in list

>>>


Список имеет метод-счетчик count(), который вернет нам количество одинаковых элементов по их содержимому.

>>> a

['Red', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>> a.count("Green")

1

>>> a.count("Black")

0

>>> a.count("Red")

2

>>>


Мы имеем возможность отсортировать список по алфавиту или по ряду чисел методом sort(), взависимости от типа данных представленных в списке. Мы можем сортировать по алфавиту a-z(а-я) -+, так и в обратном порядке, указав опциональный аргумент reverse=True.

>>> a

['Red', 'Red', 'Pink', 'Magenta', 'Grey', 'Green', 'Blue']

>>> a.sort() # Сортировка списка по алфавиту

>>> a

['Blue', 'Green', 'Grey', 'Magenta', 'Pink', 'Red', 'Red']

>>>


Метод reverse(), позволяет зеркально перевернуть список.

>>> a = ["Red", "Green", "Blue", "Magenta", "Pink", "Red", "Grey"]

>>> a.reverse()

>>> a

['Grey', 'Red', 'Pink', 'Magenta', 'Blue', 'Green', 'Red']

>>>


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

Списки в Python, могут быть вложенными, так называемыми двухмерными, трехмерными и Т.Д. Обычно вложенность списков не превышает 3х уровней. Происходит это более чем очевидно.

>>> a = [["Cat", "Dog"],["Buratino", "Pinokio"],["Red", "Green"]]

>>> a

[['Cat', 'Dog'], ['Buratino', 'Pinokio'], ['Red', 'Green']]

>>> a[0]

['Cat', 'Dog']

>>> a[1]

['Buratino', 'Pinokio']

>>> a[2]

['Red', 'Green']

>>> a[0][0]

'Cat'

>>> a[0][1]

'Dog'

>>> a[2][0]

'Red'

>>> a.append(["Minitrol", "Maxsitrol"])

>>> a

[['Cat', 'Dog'], ['Buratino', 'Pinokio'], ['Red', 'Green'], ['Minitrol', 'Maxsit

rol']]

>>> a[3]

['Minitrol', 'Maxsitrol']

>>> a[3].append("Trol")

>>> a

[['Cat', 'Dog'], ['Buratino', 'Pinokio'], ['Red', 'Green'], ['Minitrol', 'Maxsit

rol', 'Trol']]

>>> a[3]

['Minitrol', 'Maxsitrol', 'Trol']

>>> a.pop()

['Minitrol', 'Maxsitrol', 'Trol']

>>> a

[['Cat', 'Dog'], ['Buratino', 'Pinokio'], ['Red', 'Green']]

>>> len(a) # Вернет количество вложенных списков

3

>>> len(a[0]) # Вернет количество элементов в первом подсписке

2

>>>


Из этой "игры" со списком, видно, что обращаясь при помощи индексов к подспискам, мы можем взаимодействовать с ними стандартными методами списков.

Помните, мы говорили про переменные, которые ссылаются на один и тотже объект? Как же нам создать копию списка и присвоить ее какой-то переменной, так, чтобы это получились 2 независимых объекта? Очень просто. Нам необходимо заключить переменную передаваемого списка или переменную которая на него ссылается в функцию list().

>>> a

['Red', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>> b = list(a)

>>> a[0] = "Cat"

>>> a

['Cat', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>> b

['Red', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>> b[0] = "Dog"

>>> b

['Dog', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>> a

['Cat', 'Green', 'Blue', 'Magenta', 'Pink', 'Red', 'Grey']

>>>


Как видно из примера, такой синтаксис присваивания одной переменной, которая ссылается  на объект списка другой переменной, создает для последней независимую копию этого объекта.


Словари и методы словарей



Словари - это неупорядоченные списки(коллекции) элементов с доступом по ключу. Роль индекса в словаре выполняет буквенно-цифровой ключ. Словари еще известны под такими названиями, как ассоциативные массивы или хеш-таблицы. Объявление словаря происходит следующими способами:

>>> a = {}

>>> a

{}

>>>


Это создание пустого словаря.

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

>>> a = {"cat": "White", "dog": "Black"}

>>> a

{'dog': 'Black', 'cat': 'White'}

>>> a["cat"]

'White'

>>> a["dog"]

'Black'

>>>


Еще один способ создания словаря, через функцию dict():

>>> a = dict(cat="White", dog="Black")

>>> a

{'dog': 'Black', 'cat': 'White'}

>>> a["cat"]

'White'

>>> a["dog"]

'Black'

>>>


Есть метод fromkeys(), который позволяет создать словарь с несколькими ключами и с одинаковыми значениями. Первым аргументом функции, передается список ключей, вторым - значение для этих ключей. Если опустить второй аргумент, будет создан словарь с пустыми ключами, а вернее со значением "None", которое мы будем рассматривать в следующих темах.

>>> a = dict.fromkeys(["color_one", "color_two"], "Blue")

>>> a

{'color_one': 'Blue', 'color_two': 'Blue'}

>>>


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

>>> a = {}

>>> a["color"] = "Blue"

>>> a

{'color': 'Blue'}

>>> a["animal"] = "Cat"

>>> a

{'color': 'Blue', 'animal': 'Cat'}

>>>


Если указать существующий ключ и значение, оно будет перезаписанным.

>>> a

{'color': 'Blue', 'animal': 'Cat'}

>>> a["color"] = "Black"

>>> a

{'color': 'Black', 'animal': 'Cat'}

>>>


Метод clear(), очищает словарь:

>>> a

{'color': 'Black', 'animal': 'Cat'}

>>> a.clear()

>>> a

{}

>>>


Метод items(), возвращает список кортежей (ключ, значение) и применяется для преобразования словаря в список:

>>> a

{'color': 'Black', 'animal': 'Cat'}

>>> a.items()

[('color', 'Black'), ('animal', 'Cat')]

>>>


Метод keys(), возвращает список ключей, а values(), список значений словаря:

>>> a

{'color': 'Black', 'animal': 'Cat'}

>>> a.keys()

['color', 'animal']

>>> a.values()

['Black', 'Cat']

>>>


Метод pop(), как и в списке, позволяет удалять пару ключ-значение по ключу и возвращает удаляемое значение:

>>> a

{'color': 'Black', 'animal': 'Cat'}

>>> a.pop("color")

'Black'

>>> a

{'animal': 'Cat'}

>>> a.pop("animal")

'Cat'

>>> a

{}

>>>


Для создания независимой копии объекта словаря, существует метод copy():

>>> a

{}

>>> b = a.copy()

>>> b

{}

>>> a

{}

>>> a["color"] = "Green"

>>> a

{'color': 'Green'}

>>> b

{}

>>> b["color"] = "Blue"

>>> b

{'color': 'Blue'}

>>> a

{'color': 'Green'}

>>>



Преобразование типов словарь-список, список-словарь



Для преобразования словаря в список, используется метод items(), который возвращает список кортежей пар (ключ, значение), что было показано в примере выше.

Для преобразования списка в словарь, список должен иметь список подсписков [ключ, значение]:

>>> a = [["color", "Red"],["animal", "Cat"]]

>>> a

[['color', 'Red'], ['animal', 'Cat']]

>>> dict(a)

{'color': 'Red', 'animal': 'Cat'}

>>>

1 комментарий:

  1. Очень информативный блог, в закладки, автору большое спасибо за труды.

    ОтветитьУдалить