Свойства и методы
У данных обычно есть важные атрибуты и методы. Они определяют поведение и возможности этих данных. Подробнее о них можно узнать в объектно-ориентированном программировании. В этой статье рассмотрим основы работы с методами в Python.
Атрибуты и методы
Атрибуты (attributes) — это переменные, которые хранят данные в объектах классов. У каждого объекта класса есть свой набор атрибутов, которые могут быть доступны для чтения и записи.
Методы (methods) — это функции, которые связаны с определенными объектами данных.
Атрибуты и методы являются такими же выражениями, как переменные и вызовы функций. Также они могут использоваться в комбинации с другими выражениями.
Объекты
В программировании происходит взаимодействие с данными, создание чисел и строк, и выполнение над ними различных операций. Чтобы выполнить операцию, применяются либо операторы, либо функции:
# Сложение с помощью оператора +
3 + 3 # 6
# Подсчет длины с помощью функции len()
name = 'Python'
len(name) # 6
В примере выше есть четкое разделение: данные отдельно, функции отдельно. Но это не единственный способ организации кода. В Python наравне с таким разделением используется и другой подход — объектно-ориентированный(ОО).
Объектно-ориентированный код строится на объединении данных и функций в одну сущность — объект. Данные в таком случае называются атрибутами, а функции — методами.
Вот пример:
name = 'Python'
# Метод upper()
upper_name = name.upper()
print(upper_name) # => 'PYTHON'
Строки в Python — это объекты. В примере выше мы вызываем метод, то есть функцию, которая связана со строкой. Вызов происходит через точку, которая идет сразу за именем переменной. В остальном методы работают как обычные функции.
Также вызов можно делать и напрямую:
'Python'.upper() # 'PYTHON'
В строки встроено много методов, которые постоянно нужны разработчику. Посмотреть их список можно в документации. Вот несколько полезных примеров:
name = 'Python'
# Возвращает индекс первого вхождения буквы в строку
name.find('t') # 2
# Переводит в нижний регистр
name.lower() # 'python'
# Заменяет одну подстроку другой
name.replace('on', 'off') # 'Pythoff'
То же самое касается чисел и остальных типов данных. Можно сказать, что в Python почти всё является объектом:
x = -10
# Возвращает модуль числа
# Имя выглядит странно, но это действительно имя метода
x.__abs__()
В примере выше есть имя метода, в начале и конце которого по два подчеркивания. В Python так называют методы, которые не предназначены для прямого вызова. Для них создали функции, которые внутри себя уже сами вызывают методы:
x = -10
abs(x) # вызывает x.__abs__()
# -10 в 3 степени
pow(x, 3) # вызывает x.__pow__(3)
Создатель Python решил, что будет нагляднее, если математические или похожие на математические операции выразить функциями. Он хотел, чтобы такие функции воспринимались как операции, типа сложения или вычитания. Так привычнее для тех, кто изучал математику. Так же работает и функция len().
Кроме методов у объектов есть атрибуты, но у встроенных в Python объектов их мало. Например, атрибут __doc__, который возвращает документацию функции. Поэтому функции тоже считаются объектами:
len.__doc__ # 'Return the number of items in a container.'
Атрибуты работают и выглядят как переменные, только указываются через точку после объекта. Теперь поговорим про неизменяемость типов данных.
Неизменяемость
Допустим есть такой вызов:
name = 'Python'
print(name.upper()) # => PYTHON
# Что напечатает на экран этот вызов?
print(name) # => ?
Вызов метода .upper() возвращает новое значение, в котором все буквы преобразованы в верхний регистр, но он не меняет исходную строку. Поэтому внутри переменной окажется старое значение: 'Python'. Эта логика справедлива для методов всех примитивных типов.
Вместо того, чтобы изменять значение, можно заменить значение. Для этого понадобятся переменные:
name = 'Python'
name = name.upper()
print(name) # => PYTHON
Методы выражения
Методы — такие же выражения, как переменные и вызовы функции, значит, их можно по-разному комбинировать.
Например, использовать в операциях:
name = 'Alex'
'Hello, ' + name.upper() + '!' # Hello, ALEX!
Или использовать в аргументах функций:
name = 'Alex'
print(name.lower()) # => alex
n1, n2 = 2, 32
# bit_length() — вычисляет количество бит, необходимых для представления числа в двоичном виде
print((n1 + n2).bit_length()) # 6
Цепочка методов
Рассмотрим, как комбинировать различные подходы, когда пишем код, а также разберем типичные ошибки новичков. У нас есть следующий код:
name = 'Python'
print(name.upper().lower()) # => `python`
Он напечатал на экране python.
Синтаксис нескольких подряд идущих точек мы видим впервые, но все операции, которые здесь встречаются, нам знакомы. В этом коде объединились известные возможности языка. Такое в программировании происходит часто. Если вы не знаете синтаксис, то можно все равно пробовать комбинировать различные подходы, и есть вероятность, что они заработают. Чтобы понять, как работает этот код, нужно разбить цепочку на отдельные операции:
name = 'Python'
upper_name = name.upper() # 'PYTHON'
print(upper_name.lower()) # 'python'
Первый и второй примеры эквивалентны. Мы можем выполнять операции последовательно с промежуточным созданием переменных, а можем строить непрерывную цепочку из атрибутов и методов. В цепочках вычисления всегда идут слева направо. Еще один пример для закрепления:
name = 'Python'
print(name.replace('Py', 'Ti').lower()) # => ?
Над этим кодом нужно хорошо подумать. .lower() применяется к результату вызова метода, который находится левее. А метод replace() возвращает строку. Новички часто делают ошибки в цепочках с методами и забывают ставить вызов:
name = 'Python'
# Этот код отработает неверно!
print(name.upper.lower())
Также можно строить бесконечно длинные и бесполезные цепочки, которые включают в себя срезы:
name = 'Python'
# Чему равен результат такого вызова?
print(name[1:5].upper().find('Y'))
С функциями это не сработает, так как обычно они вкладываются друг в друга — f(f(f())). Это значительно усложняет анализ. Но это не значит, что нельзя сделать красиво. В других языках это реализуется через композицию функций или pipeline-оператор.
Стандартная библиотека
Python поставляется с набором полезных функций, которые составляют стандартную библиотеку. Обычно в нее входят тысячи функций, которые невозможно запомнить. Поэтому программист должен знать, где найти документацию по этим функциям, а также представлять результат, который хочет получить. По этим причинам программировать без интернета сложно.
Новички часто не понимают, как и где узнавать про функции, которые нужно использовать. При этом нет способа, который поможет решить эту проблему. По мере работы разработчики становятся опытнее, пополняют свой багаж знаний и практик. Постепенно они знакомятся с более интересными функциями, которые решают их задачи по-другому.
Вот советы, которые помогут повысить уровень профессионализма:
- Всегда отслеживайте, с каким типом данных вы работаете. Так вы найдете необходимую функцию в соответствующем разделе документации. Например, для работы со строками нужно изучать строковые функции
- Периодически открывайте раздел со стандартными функциями по вашей тематике, изучайте сигнатуры и способы использования
- Чаще читайте чужой код на GitHub. Особое внимание обращайте на код библиотек, которые используете в своем коде
Если следовать этим советам и внимательно относиться к деталям, то уже скоро вы заметите, как развиваетесь и растете как профессионал.
Полезная ссылка: Стандартная библиотека Python3 на русском.
Попробуйте сами запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает. Для этого в ячейке с кодом нажмите клавиши на клавиатуре Shift+Enter или запустите код через кнопку Run по значку ▶.