Типизация в Python
Очень часто языки программирования сравнивают по их типизации. Иначе говоря — по тому, как устроена их система типов. Давайте разберемся, какая типизация у Python, и что это означает.
Типизация в Python
Для начала мы можем смело сказать, что типизация в Python существует, а следовательно, он относится к типизированным языкам. У многих низкоуровневых языков (вроде ассемблера) вообще нет типизации — любые структуры в них — не более чем набор битов. Типизация позволяет упростить процесс обработки информации. Если данные имеют тип, то машина будет взаимодействовать с ними по правилам, установленным для этого типа.
Неявная типизация
Неявная типизация подразумевает возможность создавать объекты, не указывая их тип.
a = 1 # int
b = 1.1 # float
c = 'a' # str
Если бы в Python была явная типизация, приходилось бы каждый раз указывать тип любой переменной. Но и у нее есть свои плюсы. Например, иногда полезно указывать, данные каких типов принимает функция, метод или аргумент. Впрочем, Python позволяет и такое:
def func(a: int, b: str) -> float:
return round(float(a / len(b)), 2)
var: float = func(3, [1, 1, 1]) # 1.0
# Expected type 'str', got 'list[int]' instead
Это называется аннотацией типов. Ее возможности сильно расширяет модуль typing
, активно развивающийся с версии Python 3.5. Аннотации никак не влияют на выполнение программы, но IDE может считывать их и предупреждать, если вы использовали не тот тип.
Сильная типизация
Python - язык с сильной типизацией. Это означает, что различные типы нельзя смешивать в одних выражениях.
2 + '2'
# Traceback (most recent call last):
# File "C:\main.py", line 1, in <module>
# 2 + '2'
# ~~^~~~~
# TypeError: unsupported operand type(s) for +: 'int' and 'str'
Если бы Python был языком со слабой типизацией, результатом выполнения такого кода стало бы 22
. В ситуации, когда смешиваются разные типы, слабо типизированные языки могут неявно приводить значения к одному из них. Иногда это вызывает непредсказуемые последствия, например, если по неосторожности использовать строку с цифрами вместо числа. Однако Python допускает подобное в некоторых случаях:
2 + 2.2
# 4.2
Типы int
и float
могут свободно взаимодействовать. Это продиктовано удобством и естественностью таких преобразований.
Сами понятия "сильной" и "слабой" типизации довольно размыты и зависят от множества конкретных решений при разработке языка. Правильнее будет говорить, что какие-то языки более сильные, чем другие.
Динамическая типизация
Python - язык с динамической типизацией. Это означает, что с определенным типом связывается не переменная, а ее значение. Если бы Python был языком со статической типизацией, мы бы не смогли сделать так:
a = 1
a = 'a'
a = SomeClass()
Динамическая типизация - одна из причин популярности Python. Для начала, это просто удобно. Программа может менять типы переменных на лету, пользуясь их особенностями.
a = (1, 1, 1, 3, 1, 1)
a = list(set(a))
# [1, 3]
Не менее важно то, что динамическая типизация позволяет максимально естественно абстрагироваться от типов и заниматься обобщенным программированием.
def second(a):
try:
return a[1]
except TypeError:
return None
second([1, 2]) # 2
second('abcd') # b
second(1) # None
Однако за такое удобство приходится платить. Динамическая типизация, вместе с интерпретацией кода, стала причиной главнейшего проклятия Python - низкой скорости работы. К тому же, в языках со статической типизацией есть свои механизмы обобщенного программирования, использующие шаблоны или дженерики.
Утиная типизация
"If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck."
В Python применяется утиная типизация. Это означает, что тип данных не имеет значения — важно лишь то, какие методы и свойства они поддерживают. Например, чтобы узнать, длину объекта, мы можем использовать функцию len()
. Она не проверяет, к какому типу относится объект, а всего лишь обращается к магическому методу __len__()
. Можно узнать длину любого объекта, у которого он прописан (не важно, как именно). И наоборот, объект с очевидной длиной, но без метода __len__()
нельзя обработать этой функцией.
class SomeClass:
length = 12
def __len__(self):
return self.length
len('123')
# 3
len([1, 2])
# 2
len(SomeClass())
# 12
len(123)
# Traceback (most recent call last):
# File "C:\main.py", line 13, in <module>
# len(123)
# TypeError: object of type 'int' has no len()
Заключение
Каждый из вариантов типизации имеет свои преимущества и недостатки. Создатели языков программирования выбирали их комбинации, исходя из своих целей. Гвидо Ван Россум хотел сделать Python максимально удобным и понятным. Благодаря неявной, динамической и утиной типизации, программы на Python выходят лаконичными и простыми для понимания. В то же время, Python имеет строгую типизацию, почти не допускающую неявных преобразований.
Возможно будет интересно
🏆 Hello, world!
Мы вчера запустили новый www.pylot.me. Должны были в следующую среду, но запустили вчера.
Как практиковаться в Python?
Для улучшения качества знаний и повышения уровня программиста, необходим постоянный практикум. Где можно это организовать самостоятельно, и как практиковаться в Python?