{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "(dynamic_types)=\n", "# Динамическая типизация \n", "\n", "Следующий код `python` исполняется без ошибок." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 \n", "0.0 \n", "zero \n", "[0, 0.0, 'zero'] \n" ] } ], "source": [ "a = 0 # a - переменная типа int\n", "print(a, type(a))\n", "a = 0. # теперь a - переменная типа float\n", "print(a, type(a))\n", "a = \"zero\" # теперь a - переменная типа str\n", "print(a, type(a))\n", "a = [0, 0., \"zero\"] # теперь a - переменная типа list\n", "print(a, type(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Кажется, что переменная `a` меняет свой тип 3 раза. Как это возможно? Чтобы ответить на этот вопрос, вспомним, как это устроенно в `C/C++`.\n", "```{note}\n", "Функция [type](https://docs.python.org/3/library/functions.html#type) спрашивает у объекта его тип. \n", "```\n", "## Статическая типизация в `C/C++`\n", "\n", "Рассмотрим следующий код на языке `C/C++`.\n", "\n", "```c++\n", "int main(){\n", " char a; // 1\n", " a = 42; // 2\n", " return 0;\n", "}\n", "```\n", "\n", "В примере объявляется переменная `a` типа `char`, а затем ей присваивается целочисленное значение `42`.\n", "- При объявлении переменной выделяется блок оперативной памяти компьютера, достаточный для ее хранения (1 байт в данном случае). Эта память будет иметь фиксированный адрес (адрес переменной) `&a1`.\n", "- В следующей строке значение `42` типа `int` приводится к `char` и записывается в ячейку памяти, связанную с переменной `a`. Это возможно, потому что компилятору известно какого типа переменная `a`.\n", " \n", "\n", "Итого, опуская технические подробности:\n", "- переменная соответствует области в памяти;\n", "- оператор присвоения `=` записывает значение справа от него в область памяти, именованную переменной слева от него. \n", "\n", "## Динамическая типизация в `python`\n", "\n", "В `python` тип хранится не в переменной, а в самом объекте, а сама переменная всего лишь ссылается на объект (в `python` всё объекты), ничего не подозревая о типе этого самого объекта. На самом деле переменная в `python` представляет собой обертку над указателем `C/C++`, который всегда автоматически разыменовывается, а оператор присвоения `=` связывает переменную слева от него с объектом справа от него (изменяет значение указателя).\n", "\n", "```{note}\n", "В связи с этим, иногда термин **\"переменная\"** (**variable**) избегается в отношении python и заменяется терминами \"имя\" (**name**), \"ссылка\" (**reference**) или идентификатор. \n", "```\n", "```{note}\n", "В python работать с адресами памяти напрямую невозможно. Единственное исключение составляет функция `id`, которая в некоторых реализациях возвращает адрес памяти (целое число), где хранится объект. Эта функция нужна только для того, чтобы всегда можно было выяснить, ссылаются ли два имени на один и тот же объект. Обратится по этому адресу средствами python невозможно. \n", "```\n", "\n", "Теперь рассмотрим аналогичный код в python.\n", "```python\n", "a = 0 # 1\n", "a = 42 # 2\n", "```\n", "Первая инструкция `a=0`. Сначала вычисляется значение выражения справа. Создается объект типа `int` содержащий в себе значение `0`. Так как имени `a` до этого объявлено не было, то такое имя создаётся и связывается с объектом справа.\n", " ```{figure} /_static/lecture_specific/dynamic_typed_language/a0.svg\n", " :name: ais0\n", " ```\n", "\n", "Следующая инструкция `a = 42`. Создаётся объект типа `int`, содержащий значение `42`. Имя `a` связывается с новым объектом. \n", "```{figure} /_static/lecture_specific/dynamic_typed_language/a42.svg\n", " :name: ais42\n", "```\n", "\n", "Расширим пример ещё одной командой `a=\"s\"`.\n", "```python\n", "a = 0 # 1\n", "a = 42 # 2\n", "a = \"s\" # 3\n", "```\n", "\n", "Новая инструкция `a=\"s\"`. Создаётся объект типа `str`, содержащий значение `\"s\"`. Имя `a` связывается связывается с новым объектом, который имеет другой тип. \n", "```{figure} /_static/lecture_specific/dynamic_typed_language/as.svg\n", " :name: aiss\n", "```\n", "\n", "```{note}\n", " Иногда говорят, что тип объекта \"живёт\" в самом объекте, а не в \"переменной\". \n", "```\n" ] } ], "metadata": { "interpreter": { "hash": "eea3ef54c04064aa17c056cc2578c78db8b44278034b77b7225a3166c34cea02" }, "kernelspec": { "display_name": "Python 3.8.10 ('venv': venv)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }