05.07.2019       Выпуск 289 (01.07.2019 - 07.07.2019)       Статьи

5 распространенных ошибок начинающих программистов на Python

В первые дни работы программистом на Python все мы сталкиваемся с разными типами багов в нашем коде, которые после нескольких болезненных часов в StackOverflow оказываются не багом, а фичей Python'а. Ниже приведены 5 самых распространенных ошибок, которые делают большинство начинающих программистов на Python. Давайте немного о них узнаем, чтобы сэкономить несколько часов, задавая вопросы на страницах и в группах в Facebook.

Читать>>




Экспериментальная функция:

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

Просим обратить внимание, что текст по ссылке и здесь может не совпадать.

В первые дни работы программистом на Python все мы сталкиваемся с разными типами багов в нашем коде, которые после нескольких болезненных часов в StackOverflow оказываются не багом, а фичей Python'а. Ниже приведены 5 самых распространенных ошибок, которые делают большинство начинающих программистов на Python. Давайте немного о них узнаем, чтобы сэкономить несколько часов, задавая вопросы на страницах и в группах в Facebook.

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].

Бонус: Не надо смешивать пробелы и табы. Просто не надо.





Разместим вашу рекламу

Пиши: mail@pythondigest.ru

Нашли опечатку?

Выделите фрагмент и отправьте нажатием Ctrl+Enter.

Система Orphus