Добрый день, уважаемые читатели. Сегодня я хотел бы обсудить некоторые странные вещи, которые происходят с нашим любимым ЯП Python, и дать пищу для размышлений над, казалось бы, очевидными вещами.
Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!
Что такое range, map, dict, tuple?
Первый пункт этой статьи связан с range()
, map()
, dict()
, tuple()
, которые очень часто называются функциями, хотя это не совсем так.
Дело в том, что, оказуется, это не функции. Воспользуемся функцией (!) type
для определения типа объекта.
import sys
type(range), type(sum)
-----------------------------------------------
(type, builtin_function_or_method)
Типы range
и sum
не совпадают. Python утверждает, что range
— это тип, а sum
— встроенная функция или метод. Попробуем создать свою функцию и выяснить её тип.
def f() -> None: pass type(f) ----------------------------------------------- function
Ожидаемо, созданная пользователем функция имеет тип function
. А теперь создадим свой класс и также воспользуемся type
.
class C: pass type(C) ----------------------------------------------- type
Вот оно! Типы range
и нашего класса совпадают. Получается, range
— это класс, а используя передачу параметров, мы используем конструктор класса, который действительно создает объект range
.
Проверим типы других известных «функций»:
type(tuple), type(list), type(map) ----------------------------------------------- (type, type, type)
Получается, tuple
, list
и map
это также классы, а передача параметров в круглых скобках — вызов конструктора класса. Если для tuple
и list
это утверждение более очевидно, то для map
этот факт действительно удивительный.
Таким образом, фраза «используем функцию map» уже звучит не так «убедительно». Для себя я решил, что далее буду использовать фразу «используем map, для того, чтобы …», т. е. не буду называть map функцией.
Немного про изменяемость кортежей
В этом разделе я приведу один очень заезженный пример, однако при обсуждении странностей python я не мог не упомянуть это.
Не углубляясь в определения, мы знаем, что кортеж — неизменяемый. Однако, как оказалось, мы можем изменять объекты внутри кортежа.
t = (1, 2, 3, [4, 5]) t[3].append(6) t ----------------------------------------------- (1, 2, 3, [4, 5, 6])
И, конечно же, этот приём работает и для словарей.
t = ({1:2}, {3:4}, {}) t[2][5] = 6 t ----------------------------------------------- ({1:2}, {3:4}, {5:6})
Но такой кортеж не является хэшируемым, т. к. содержит в себе нехэшируемые объекты.
{t:1} ----------------------------------------------- TypeError: unhashable type: 'dict'
И всё же, такая возможность изменять объекты внутри кортежа кажется странной.
Проблемы именованных параметров
Последней проблемой, которую мы обсудим, будет связана с именованными параметрами функции. Разберём следующий фрагмент кода:
def append_zero(l=[]): l.append(0) return l l1 = append_zero() print(l1) l2 = append_zero() print(l2) l1 is l2 ----------------------------------------------- [0] [0, 0] True
Проблема на лицо. Эта проблема связана с ссылочной системой Python. Чтобы решить эту проблему, всего лишь немного поменяем функцию.
def append_zero(l=None): if l is None: l = list() l.append(0) return l l1 = append_zero() print(l1) l2 = append_zero() print(l2) l1 is l2 ----------------------------------------------- [0] [0] True
Теперь всё работает ожидаемо. Приведу ещё один пример трудностей с ссылками.
a = [0, 1] b = a b.append(2) a ----------------------------------------------- [0, 1, 2]
Таким образом, оператор присваивания присваивает не значение, а ссылку для изменяемых типов. Советую подробнее ознакомиться с этим аспектом хранения объектов в памяти, благо информации в сети море.
Заключение
В этой статье мы обсудили некоторые странности и проблемы, которые могут возникнуть у новичка и не только при использовании языка программирования Python. Разумеется, это далеко не все странности, с которыми вы можете столкнуться. Советую попробовать обнаружить какую-то странность самостоятельно. Это довольно увлекательный процесс.
Советую прочитать статью «Бросок тела с высоты, моделируем на Python«.
А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.