Динамическая типизация
Contents
Динамическая типизация¶
Следующий код python
исполняется без ошибок.
a = 0 # a - переменная типа int
print(a, type(a))
a = 0. # теперь a - переменная типа float
print(a, type(a))
a = "zero" # теперь a - переменная типа str
print(a, type(a))
a = [0, 0., "zero"] # теперь a - переменная типа list
print(a, type(a))
0 <class 'int'>
0.0 <class 'float'>
zero <class 'str'>
[0, 0.0, 'zero'] <class 'list'>
Кажется, что переменная a
меняет свой тип 3 раза. Как это возможно? Чтобы ответить на этот вопрос, вспомним, как это устроенно в C/C++
.
Note
Функция type спрашивает у объекта его тип.
Статическая типизация в C/C++
¶
Рассмотрим следующий код на языке C/C++
.
int main(){
char a; // 1
a = 42; // 2
return 0;
}
В примере объявляется переменная a
типа char
, а затем ей присваивается целочисленное значение 42
.
При объявлении переменной выделяется блок оперативной памяти компьютера, достаточный для ее хранения (1 байт в данном случае). Эта память будет иметь фиксированный адрес (адрес переменной)
&a1
.В следующей строке значение
42
типаint
приводится кchar
и записывается в ячейку памяти, связанную с переменнойa
. Это возможно, потому что компилятору известно какого типа переменнаяa
.
Итого, опуская технические подробности:
переменная соответствует области в памяти;
оператор присвоения
=
записывает значение справа от него в область памяти, именованную переменной слева от него.
Динамическая типизация в python
¶
В python
тип хранится не в переменной, а в самом объекте, а сама переменная всего лишь ссылается на объект (в python
всё объекты), ничего не подозревая о типе этого самого объекта. На самом деле переменная в python
представляет собой обертку над указателем C/C++
, который всегда автоматически разыменовывается, а оператор присвоения =
связывает переменную слева от него с объектом справа от него (изменяет значение указателя).
Note
В связи с этим, иногда термин “переменная” (variable) избегается в отношении python и заменяется терминами “имя” (name), “ссылка” (reference) или идентификатор.
Note
В python работать с адресами памяти напрямую невозможно. Единственное исключение составляет функция id
, которая в некоторых реализациях возвращает адрес памяти (целое число), где хранится объект. Эта функция нужна только для того, чтобы всегда можно было выяснить, ссылаются ли два имени на один и тот же объект. Обратится по этому адресу средствами python невозможно.
Теперь рассмотрим аналогичный код в python.
a = 0 # 1
a = 42 # 2
Первая инструкция a=0
. Сначала вычисляется значение выражения справа. Создается объект типа int
содержащий в себе значение 0
. Так как имени a
до этого объявлено не было, то такое имя создаётся и связывается с объектом справа.
Следующая инструкция a = 42
. Создаётся объект типа int
, содержащий значение 42
. Имя a
связывается с новым объектом.
Расширим пример ещё одной командой a="s"
.
a = 0 # 1
a = 42 # 2
a = "s" # 3
Новая инструкция a="s"
. Создаётся объект типа str
, содержащий значение "s"
. Имя a
связывается связывается с новым объектом, который имеет другой тип.
Note
Иногда говорят, что тип объекта “живёт” в самом объекте, а не в “переменной”.