1. Копирование словарей или списков
Когда вам надо сделать копию словаря или списка, недостаточно просто использовать оператор присваивания.
Неправильно:
>>> dict_a = {"name": "John", "address":"221B Baker street"} >>> dict_b = dict_a
Теперь, если вы меняете или обновляете dict_b, то dict_a тоже будет изменен — и все это благодаря оператору присваивания. Используя этот оператор, вы пытаетесь сказать, что dict_b будет указывать на тот же самый объект, что и dict_a.
>>> dict_b["age"] = 26 >>> dict_b {'address': '221B Baker street', 'name': 'John', 'age': 26} >>> dict_a {'address': '221B Baker street', 'name': 'John', 'age': 26} >>>
Правильно: использовать методы copy() или deepcopy().
>>> dict_c = dict_b.copy() >>> dict_c["location"] = "somewhere" >>> dict_c {'address': '221B Baker street', 'name': 'John', 'age': 26, 'location': 'somewhere'} >>> dict_b {'address': '221B Baker street', 'name': 'John', 'age': 26} >>> dict_a {'address': '221B Baker street', 'name': 'John', 'age': 26} >>>
См. разницу между copy и deepcopy.
2. Ключи словарей
Давайте попробуем добавить значения в словарь:
>>> dict_a = dict() >>> dict_a {} >>> dict_a[1] = "apple" >>> dict_a[True] = "mango" >>> dict_a[2] = "melon"
Если мы попробуем вывести словарь на экран, что мы увидим?
>>> dict_a {1: 'mango', 2: 'melon'}
Что случилось, где ключ True?
Надо помнить, что класс Boolean наследуется от Integer (целых чисел). А целое число, эквивалентное True — это 1; эквивалент False — это 0. Значит, значение по ключу 1 просто переписывается.
>>> isinstance(True, int) True >>> isinstance(False, int) True >>> True == 1 True >>> False == 0 True
3. Обновление списков или словарей
Допустим, вы хотите добавить элемент в список.
>>> list_a = [1,2,3,4,5] >>> list_a = list_a.append(6) >>> list_a >>> # prints nothing
Или пытаетесь обновить словарь.
>>> dict_a = {"a" : "b"} >>> dict_a = dict_a.update({"c" : "d"}) >>> dict_a >>> # prints nothing
А теперь давайте попробуем упорядочить список.
>>> list_b = [2,5,3,1,7] >>> list_b = list_b.sort() >>> list_b >>> # prints nothing
Почему ничего не выводится, что мы делаем не так?
Большинство методов контейнеров (такие как sort, update, append, add, и т. д.) соптимизированы в целях производительности — и избегают ненужного создания отдельных копий.
Не пытайтесь присвоить возвращаемое значение таких методов в переменную.
Правильно:
>>> list_a = [1,2,3,4,5] >>> list_a.append(6) >>> dict_a = {"a" : "b"} >>> dict_a.update({"c" : "d"}) >>> dict_a {'c': 'd', 'a': 'b'} >>> list_a.sort() >>> list_a [1, 2, 3, 4, 5, 6]
4. Интернированные (Interned) строки
В некоторых случаях Python пытается переиспользовать существующие неизменяемые объекты. Интернирование строки — это один из таких случаев.
>>> a = "gmail" >>> b = "gmail" >>> a is b True
Здесь мы пытались создать два различных объекта — строки. Но когда мы проверили их на эквивалентность, выяснилось, что они полностью совпадают. Такое происходит из-за того, что Python не создал другого объекта b, а сделал b указывающим на первое значение «gmail».
Все строки длиной 1 являются интернированными. Строки, в которых есть что-то за исключением ASCII-символов, цифр и знака подчеркивания, не будут интернированными.
Давайте проверим.
>>> a = "@gmail" >>> b = "@gmail" >>> a is b False
Также надо запомнить, что == отличается от оператора is. Оператор == проверяет, являются ли значения эквивалентными или нет, тогда как оператор is проверяет, ссылаются ли обе переменные на один и тот же объект.
>>> a = "@gmail" >>> b = "@gmail" >>> a is b False >>> a == b True
Так что помните про это, когда используете неизменяемые строки или операторы == и is.
5. Аргументы по умолчанию вычисляются один раз
Рассмотрим пример:
def func(a, lst=[]): lst.append(a) return lst print(func(1)) print(func(2))
Как вы думаете, что будет выведено после двух принтов?
Давайте запустим код.
>>> def func(a, lst=[]): ... lst.append(a) ... return lst ... >>> print(func(1)) [1] >>> print(func(2)) [1, 2]
Почему во втором случае выводится [1, 2]? Не должно ли это быть просто [2]?
Итак, подвох в том, что аргументы по умолчанию вычисляются только один раз.При первом вызове функции — func(1) — список оценили и поняли, что он пустой. Значит, к нему можно добавить 1. Но при втором вызове — func(2) — в списке уже есть один элемент, поэтому выводится [1, 2].
Бонус: Не надо смешивать пробелы и табы. Просто не надо.
ссылка на оригинал статьи https://habr.com/ru/post/458902/
Добавить комментарий