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 обычно возникают из-за принципов и особенностей дизайна языка, и как только вы с ними познакомитесь, их часто можно использовать в своих интересах. Удачного кодирования!