Python ценится за его удобочитаемость и простоту, что делает его популярным выбором как для новичков, так и для экспертов. Однако, как и у любого другого языка программирования, у Python есть свои причуды или «подводные камни» — неожиданное поведение, которое может поставить в тупик программистов, особенно тех, кто плохо знаком с этим языком. В этом сообщении блога мы рассмотрим некоторые из наиболее распространенных ошибок Python и обсудим, как с ними справиться.

Изменяемые аргументы по умолчанию

В Python аргументы функции оцениваются один раз, когда функция определена, а не каждый раз, когда функция вызывается. Это означает, что изменяемые аргументы по умолчанию могут привести к неожиданному поведению:

def append_to_list(value, my_list=[]):
    my_list.append(value)
    return my_list

print(append_to_list(1))  # Output: [1]
print(append_to_list(2))  # Output: [1, 2]

Вы можете ожидать, что второй вызов вернет [2], но он вернет [1, 2], поскольку список my_list создается только один раз. Чтобы избежать этого, вы можете использовать None в качестве значения по умолчанию, а затем инициализировать my_list в теле функции. Вот два способа справиться с этим:

Использование явного оператора if:

def append_to_list(value, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(value)
    return my_list

print(append_to_list(1))  # Output: [1]
print(append_to_list(2))  # Output: [2]

Используя значения Python Truthy и Falsy:

def append_to_list(value, my_list=None):
    my_list = my_list or []
    my_list.append(value)
    return my_list

print(append_to_list(1))  # Output: [1]
print(append_to_list(2))  # Output: [2]

В то время как оператор if является более явным и может быть более понятным для начинающих или разработчиков, использующих другие языки, использование my_list = my_list or [] является более кратким, "Pythonic" способом обработки этого сценария. Эта идиома использует обработку Python истинных и ложных значений: пустой список, пустой словарь, None, False, 0 и пустые строки, все оцениваются как False в логическом контексте, позволяя оператору or предоставлять значение по умолчанию, когда my_list равно None. .

Область видимости переменных — глобальная и локальная

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

x = 10

def modify_global():
    x += 5
    return x

print(modify_global())  # UnboundLocalError: local variable 'x' referenced before assignment

Чтобы избежать этой ошибки, вы можете объявить x глобальным внутри функции:

x = 10

def modify_global():
    global x
    x += 5
    return x

print(modify_global())  # Output: 15

Утечка переменных в списках

В Python 2 переменная итерации в генераторах списков просачивается в глобальное пространство имен, что может привести к запутанным результатам. Однако это исправлено в Python 3:

# Python 2
x = 'Before'
dummy = [x for x in range(5)]
print(x)  # Output: 4

# Python 3
x = 'Before'
dummy = [x for x in range(5)]
print(x)  # Output: 'Before'

Если вы все еще работаете в Python 2, помните об этом и рассмотрите возможность использования другого имени переменной в понимании.

Равенство против идентичности

В Python == проверяет равенство (имеют ли два объекта одинаковое значение?), а is проверяет идентичность (являются ли два имени или переменные одним и тем же объектом?). Это может привести к некоторым неожиданностям:

x = [1, 2, 3]
y = [1, 2, 3]

print(x == y)  # Output: True
print(x is y)  # Output: False

И x, и y имеют одинаковые значения, но они не являются одним и тем же объектом, что приводит к разнице в выводе. Используйте ==, если вы хотите сравнить значения, и is, если вы хотите проверить, указывают ли две переменные на один и тот же объект.

Оператор отдела

Поведение Python для деления отличается в зависимости от версии. В Python 2 деление двух целых чисел дает целое число (полное деление), а в Python 3 — число с плавающей запятой. Это может привести к неожиданным результатам, если вы не знаете об этом:

# Python 2
print(5 / 2)  # Output: 2

# Python 3
print(5 / 2)  # Output: 2.5

В Python 2, чтобы получить деление с плавающей запятой, вы можете импортировать division из __future__ или преобразовать один из операндов в число с плавающей запятой. В Python 3, чтобы получить деление пола, используйте //.

Заключение

У каждого языка есть свои особенности, и Python не исключение. Знание этого может помочь вам избежать многочасовой отладки. Сюрпризы Python обычно возникают из-за принципов и особенностей дизайна языка, и как только вы с ними познакомитесь, их часто можно использовать в своих интересах. Удачного кодирования!