Каждый Python-разработчик в начале пути делает одни и те же ошибки. Хорошая новость — зная их заранее, ты сэкономишь часы отладки.
1. Изменение списка во время итерации
# ❌ Неправильно — список меняется прямо в цикле:
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # Пропустит элементы!
print(numbers) # [1, 3, 5] — кажется верным, но это случайность
Почему плохо: Python пропускает элементы при удалении, потому что сдвигает индексы.
# ✅ Правильно — создать новый список:
numbers = [1, 2, 3, 4, 5]
numbers = [num for num in numbers if num % 2 != 0]
print(numbers) # [1, 3, 5]
2. Мутабельный аргумент по умолчанию
# ❌ Классическая ловушка:
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("яблоко")) # ['яблоко']
print(add_item("банан")) # ['яблоко', 'банан'] — WTF?!
print(add_item("апельсин")) # ['яблоко', 'банан', 'апельсин']
Почему плохо: Список создаётся один раз при определении функции, не при каждом вызове.
# ✅ Используй None как дефолт:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("яблоко")) # ['яблоко']
print(add_item("банан")) # ['банан']
3. Сравнение с None через ==
# ❌ Работает, но неправильно стилистически:
result = None
if result == None:
print("Нет результата")
# ✅ Всегда используй is / is not:
if result is None:
print("Нет результата")
if result is not None:
print(f"Результат: {result}")
Почему: == проверяет значение, is — идентичность объекта. None — singleton, is работает корректнее и быстрее.
4. Перехват всех исключений
# ❌ Плохо — скрывает реальные ошибки:
try:
result = int(input("Введи число: "))
print(10 / result)
except:
print("Что-то пошло не так")
Если опечатался в имени переменной — ты никогда об этом не узнаешь.
# ✅ Ловить конкретные исключения:
try:
result = int(input("Введи число: "))
print(10 / result)
except ValueError:
print("Это не число!")
except ZeroDivisionError:
print("На ноль делить нельзя!")
5. Копирование списков через присваивание
# ❌ Это не копия — это ссылка на тот же объект:
original = [1, 2, 3]
copy = original
copy.append(4)
print(original) # [1, 2, 3, 4] — оригинал тоже изменился!
# ✅ Три способа сделать настоящую копию:
copy1 = original.copy()
copy2 = original[:]
copy3 = list(original)
copy1.append(4)
print(original) # [1, 2, 3] — оригинал не тронут
Для вложенных структур используй copy.deepcopy():
import copy
matrix = [[1, 2], [3, 4]]
deep = copy.deepcopy(matrix)
deep[0].append(99)
print(matrix) # [[1, 2], [3, 4]] — не изменился
6. Использование + для конкатенации строк в цикле
# ❌ Медленно — создаёт новую строку на каждой итерации:
words = ["Python", "это", "супер"]
result = ""
for word in words:
result = result + word + " "
# ✅ Используй join():
words = ["Python", "это", "супер"]
result = " ".join(words)
print(result) # Python это супер
Разница в скорости: На 10 000 строк join() быстрее в десятки раз.
7. Путаница между is и ==
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True — одинаковые значения
print(a is b) # False — разные объекты в памяти
c = a
print(a is c) # True — один и тот же объект
Правило: == — для сравнения значений. is — только для None, True, False и проверки идентичности.
8. Забытый return в функции
# ❌ Функция возвращает None вместо результата:
def multiply(a, b):
result = a * b
# Забыли return!
value = multiply(3, 4)
print(value) # None
# ✅ Всегда явно возвращай результат:
def multiply(a, b):
return a * b
value = multiply(3, 4)
print(value) # 12
9. Неправильное использование глобальных переменных
# ❌ Неожиданное поведение:
counter = 0
def increment():
counter += 1 # UnboundLocalError!
increment()
Python думает, что counter — локальная переменная (из-за +=), но она не определена локально.
# ✅ Вариант 1 — объявить global (не рекомендуется):
def increment():
global counter
counter += 1
# ✅ Вариант 2 — передавать и возвращать значение (лучше):
def increment(counter):
return counter + 1
counter = increment(counter)
10. Сравнение float на равенство
# ❌ Никогда не делай так:
result = 0.1 + 0.2
print(result == 0.3) # False — из-за погрешности float
# ✅ Используй math.isclose():
import math
print(math.isclose(result, 0.3)) # True
# Или задай допустимую погрешность:
print(abs(result - 0.3) < 1e-9) # True
11. Забытые скобки при вызове метода
# ❌ Частая ошибка — метод не вызван, а просто получена ссылка на него:
my_list = [3, 1, 2]
my_list.sort # Ничего не произошло!
# ✅ Правильно:
my_list.sort() # Сортирует на месте
print(my_list) # [1, 2, 3]
12. Использование print для отладки вместо assert
# Рабочий подход, но засоряет код:
def divide(a, b):
print(f"a={a}, b={b}") # Отладочный print
return a / b
# ✅ Используй assert для проверки условий:
def divide(a, b):
assert b != 0, "Делитель не может быть нулём"
return a / b
# ✅ Для серьёзной отладки — модуль logging:
import logging
logging.debug(f"Вызов divide({a}, {b})")
Чеклист для самопроверки 📋
Перед тем как сказать “код готов”, проверь:
✅ Не изменяю список в цикле?
✅ Нет мутабельных дефолтных аргументов?
✅ Сравниваю с None через is / is not?
✅ Ловлю конкретные, а не все исключения?
✅ Копирую списки через .copy(), а не =?
✅ Строки конкатенирую через join(), а не +?
✅ У каждой функции есть явный return?
✅ Не сравниваю float через ==?
✅ Не забыл скобки при вызове методов?
Итого 🚀
Эти ошибки не делают тебя плохим программистом — они делают тебя нормальным начинающим. Разница между джуном и опытным разработчиком не в том, что опытный не ошибается — он просто знает где искать и быстро находит.
Распечатай чеклист и держи рядом пока эти вещи не станут рефлексом. 💪
💬 Comments (0)
No comments yet
Be the first to share your opinion about this article!