Странности языка Python, которые могут вас укусить

2
15491
Добавить в избранное

У языка Python, как и у любого другого, есть совершенно непонятные моменты, которые неплохо бы разобрать «по кирпичикам». Этим и займемся.

языка Python

Хорошим способом получить максимальную отдачу от приведенных здесь примеров будет их прочтение в хронологическом порядке:

— Внимательно просмотрите исходный код примера. Если вы опытный программист на Python, то обязательно попробуете предсказать, что будет на выходе.
— Взгляните на результат и:

  1. Проверьте, совпадает ли он с тем, что вы ожидали.
  2. Попробуйте подумать, что именно стало причиной такого результата?
  • Если не смогли, прочтите объяснение.
  • Если смогли, скажите себе, что вы молодец, и переходите следующему примеру.

P.S. Вы также можете воспользоваться командной строкой, установив wtfpython:

Теперь просто запустите wtfpython в командной строке, которая откроет эту коллекцию в выбранном $PAGER.

Примеры странностей языка Python

Ну, что-то сомнительное…

Выход (Python 2.x):

Для языка Python нет невозможного, но… Разве здесь не должно быть 100?

Примечание. Если вы не можете воспроизвести это, попробуйте запустить файл mixed_tabs_and_spaces.py через оболочку.

Объяснение:

  • Не смешивайте табы и отступы! Символ, предшествующий return является «табом», а в другом месте код имеет отступ в «4 пробела».
  • Так Python обрабатывает табы: табы заменяются на один-восемь пробелов.
  • Таким образом, «таб» в последней строке заменяется на восемь пробелов, что создает цикл.
  • Python 3 достаточно хорош, чтобы автоматически выдавать ошибку для таких случаев.

Выход (Python 3.x):

Время для некоторых «хашбраунов»!

Выход:

Дискриминация со стороны языка Python? «Python» уничтожил «JavaScript»?

Объяснение:

5 (тип int) неявно преобразован в 5.0 (тип float) перед вычислением хеша Python.

Этот ответ из StackOverflow прекрасно объясняет причины.

Изменение словаря во время итерации по нему

Выход:

Объяснение:

  • Итерация по словарю, который вы редактируете, не поддерживается.
  • Эта штука срабатывает только восемь раз, ведь именно это та точка, в которой словарь должен бы изменить размер, чтобы удержать больше ключей (стандартно есть только восемь записей, поэтому меняйте размер, если нужно). Это фактически деталь реализации.
  • См. ответ StackOverflow, объясняющий аналогичный пример.

Удаление элемента списка в процессе итерации

Выход:

Вы можете догадаться, почему вывод [2, 4]?

Объяснение:

Не рекомендуется менять объект, который вы повторяете. Правильный способ сделать это – перебрать копию объекта, и list_3[:] делает именно это.

Разница между del, remove и pop для языка Python:

  • remove удаляет первое совпадающее значение, а не определенный индекс, вызывает ValueError, если значение не найдено.
  • del удаляет определенный индекс (поэтому первый list_1 не был затронут), вызывает IndexError, если указан недопустимый индекс.
  • pop удаляет элемент по определенному индексу и возвращает его, вызывает IndexError, если указан недопустимый индекс.

Почему на выходе [2, 4]?

  • Когда мы удаляем 1 из list_2 или list_4, содержимое списков становится [2, 3, 4]. Остальные элементы сдвинуты вниз, т. е. 2 ​​находится в индексе 0, а 3 – в индексе 1. Так как следующая итерация будет искать индекс 1 (который является 3), то 2 полностью пропускается. Аналогичная вещь будет происходить с каждым альтернативным элементом в последовательности списка.
  • См. этот ответ на StackOverflow с разбором аналогичного примера, связанного со словарями в Python.

Обратные косые черты в конце строки

Выход:

Объяснение:

Интерпретатор просто меняет поведение обратных косых черт, поэтому они проходят через себя и следующий символ. Вот почему обратная косая черта не работает в конце строки.

Да, он существует!

else для циклов. Одним из типичных примеров может быть:

Выход:

else в обработке исключений. Пример:

Выход:

Объяснение:

  • else после цикла выполняется только тогда, когда нет явного прерывания после всех итераций.
  • else после блока try также называется «предложением завершения», поскольку достижение else в try означает, что блок try действительно успешно завершен.

is is not what it is!

Ниже представлен известный во всем Интернете пример:

Объяснение:

Разница между is и ==:

  • is используется, если оба операнда относятся к одному и тому же объекту (то есть он проверяет соответствие совпадений операндов).
  • == сравнивает значения двух операндов.

То есть is для ссылочного равенства и == для равенства значений. Пример, чтобы прояснить ситуацию:

is not … это не is (not …)

Объяснение:

  • is not является единственным бинарным оператором и обладает поведением, отличным от использования is и not.
  • is not приводит к False, если переменные с обеих сторон оператора указывают на один и тот же объект; в противном же случае выдает True.

Функция внутри цикла и результат

Выход:

Даже когда значения x были разными на каждой итерации до добавления some_func в funcs, все функции возвращали 6.

//ИЛИ

Объяснение:

  • При определении внутри цикла функции, которая использует переменную цикла в своем теле, закрытие функции цикла привязано к переменной, а не к ее значению. Таким образом, все функции используют последнее значение, присвоенное переменной для вычисления.
  • Вы можете передать переменную цикла в качестве именованной переменной в функцию. Почему это работает? Потому что это снова определит переменную в пределах области действия.

Выход:

Остерегайтесь измененных аргументов по умолчанию!

Выход:

Объяснение:

Измененные по умолчанию аргументы функций в Python на самом деле не инициализируются каждый раз, когда вы вызываете функцию. Вместо этого в качестве значения по умолчанию используется последнее присвоенное им значение. Когда мы явно передали [] в some_func в качестве аргумента, значение по умолчанию переменной default_arg не использовалось, поэтому функция ожидаемо возвращалась.

Выход:

Чтобы избежать ошибок из-за подобных аргументов, существует назначение None, которое используется по умолчанию, а также проверка того, передано ли какое-либо значение функции, соответствующей этому аргументу. Пример:

Одинаковые операнды, разные истории!

1.

Выход:

2.

Выход:

Объяснение:

  • a += b не ведет себя так же, как a = a + b.
  • Выражение a = a + [5,6,7,8] генерирует новый объект и устанавливает ссылку a на этот новый объект, оставляя b неизменным.
  • Подробнее об этом можно прочесть здесь.

Использование переменной, не определенной в области

Выход:

Объяснение:

  • Когда вы назначаете переменную в области видимости, она становится локальной. Таким образом, переменная a становится локальной для области another_func, но ранее не была инициализирована в той же области, которая вызывает ошибку.
  • Дополнительно прочтите это краткое руководство.
  • Чтобы изменить внешнюю переменную области a в another_func, используйте глобальное ключевое слово:

Выход:

Return return everywhere!

Выход:

Объяснение:

  • Когда в try-блоке «try … finally» выполняется оператор return, break или continue, finally также выполняется «на выходе».
  • Возвращаемое значение функции определяется последним выполненным оператором return. Поскольку finally выполняется всегда, оператор return, выполняемый в finally, всегда будет последним.
Интересуетесь программированием на Python?

Подпишитесь на нашу рассылку, чтобы получать больше интересных материалов:

И не беспокойтесь, мы тоже не любим спам. Отписаться можно в любое время.




Добавить комментарий