В этом видео мы продолжим с вами разбирать то, как в Python устроены методы и связанные с ними вещи. Следующим концептом, на который мы посмотрим, является статический метод, либо staticmethod. Давайте посмотрим на примере. Может так получиться, что вам нужно объявить метод в контексте класса, но этот метод не оперирует ни ссылкой на конкретный экземпляр класса, ни самим классом непосредственно, как мы видели в методе класса. В таком случае вам может помочь статический метод. Зачем вам может понадобиться статический метод? На самом деле, статический метод — это просто вопрос организации кода, то есть вы его используете тогда, когда вам необходимо, чтобы к нему обращались относительно имени класса либо экземпляра. Давайте посмотрим на примере, как объявить статический метод. Мы объявляем class Human, у которого есть имя и возраст, и объявили статический метод is_age_valid, который проверяет возраст на соответствие каким-то возрастным ограничениям. Чтобы объявить статический метод, мы воспользовались декоратором staticmethod, опять же, это встроенный объект в Python'е, не нужно его ниоткуда импортировать. После того как мы обернули функцию декоратором staticmethod, мы получаем статический метод. Статический метод принимает только те аргументы, которые ему передают. Обратите внимание, что здесь нет ни self, ни class аргументов. Обращаться к нему можно вот так, то есть относительно имени класса самого Human, либо относительно экземпляра. И в том, и в другом случае происходит одно и то же, и код отработает. Опять же, подчеркну, что в данном случае мы могли бы эту функцию объявить просто как обычную функцию, вне контекста класса, вне пространства имен класса. Но мы решили сделать это так, просто из соображений того, что этим будет удобнее пользоваться. Далее, еще один мощный концепт, который есть в языке Python и встречается в стандартной библиотеке и в библиотеках повсеместно, является property. Property, или по-другому вычисляемые свойства. Зачем они нужны? Property позволяют изменять поведение и выполнять какую-то вычислительную работу при обращении к атрибуту экземпляра, либо при изменении атрибута, либо при его удалении. Проще всего это понять на примере. Давайте начнем немножко издалека. Предположим, у нас есть класс Robot. У этого класса есть переопределенный метод init, который инициализирует экземпляр класса одним атрибутом power — это мощность робота. Соответственно, пользоваться всем этим можно вот так, ничего нового для вас здесь нет. Мы инициализируем экземпляр и далее можем в любой момент поменять мощность робота и установить ему новое значение. Предположим, что так получилось, что вы заметили, что другие программисты, которые пользуются вашим классом Robot, иногда ставят ему отрицательную мощность, а это невалидное значение, и вам хотелось бы, чтобы когда другие программисты ставят отрицательную мощность, эта мощность на самом деле ставилась бы в ноль. Как можно поступить в таком случае? Первое, что приходит на ум, это отрефакторить наш класс и добавить метод экземпляра set_power, который, принимая мощность, будет проверять, что мощность меньше нуля и в таком случае ставить ее в ноль, либо ставить в то значение, которое нам передали. Таким образом, пользоваться этим можно уже вот так. Мы инициализируем объект Robot и дальше вызываем у него метод set_power, который в случае отрицательной мощности поставит ее в ноль, и мы видим, что у нас получилось. Однако здесь есть небольшой нюанс. В таком случае программисту, который использует ваш класс, придется менять свой код. То есть это потребует не только рефакторинга от вас, но и рефакторинга от других программистов. Есть ли способ проще? Есть. Как раз здесь и появляется property. Давайте посмотрим, что это. В данном случае это тот же самый класс Robot, у которого power теперь является объектом property. Опять же, это встроенный объект, ниоткуда не нужно его импортировать. У этого property есть на самом деле три метода — это метод getter, метод setter, и метод deleter. Все эти три метода мы можем переопределить, чтобы менять поведение и выполнять какую-то полезную работу при обращении к атрибуту, при присваивании атрибуту какого-то нового значения либо при удалении атрибута. Давайте посмотрим, как это сделано. Мы объявили class Robot, и теперь _power у него является приватным атрибутом. А power без нижнего подчеркивания теперь является объектом property. Вот таким образом он инициализируется. Далее мы можем объявить три метода и обернуть их декораторами. power.setter — это тот метод, который будет выполняться, когда мы будем менять атрибут экземпляра power. power.getter — это тот метод, который будет выполняться, когда мы будем читать атрибут power. power.deleter — это тот метод, соответственно, который будет выполняться при удалении атрибута. Внутри этих методов мы можем выполнять какую-то полезную работу. Например, в методе setter, который принимает значение, которое пользователь пытается присвоить атрибуту, мы проверяем, что это значение меньше нуля, и, соответственно, ставим приватный атрибут power в ноль. То же самое, что мы делали в методе set_power чуть ранее. Соответственно, в методе getter объекта property мы возвращаем значение приватного атрибута power. Теперь, когда другой программист будет пользоваться вашим классом, он может по прежнему использовать старый подход и ставить атрибут экземпляру. Даже если он поставит отрицательный атрибут, этот атрибут будет выставлен в ноль в итоге, потому что отработает setter метод нашего свойства, нашего property. Если мы попробуем удалить этот атрибут, то выполнится deleter метод, который мы также переопределили, и, соответственно, удалит атрибут power из нашего экземпляра, тем самым сделав робота бесполезным. Иногда нужно как-то модифицировать чтение атрибута и выполнять какую-то полезную работу при чтении, и это единственное, что вам требуется. То есть не нужно менять поведение при изменении значения атрибута либо при его удалении. В таком случае есть более короткая запись. Мы можем объявить метод, обернуть его декоратором property без всяких суффиксов getter, setter и deleter, и это будет вычисляемым свойством класса, к которому можно обращаться вот так, как вы видите на слайде, то есть просто.power. Удобно. В этом видео мы рассмотрели, что такое статический метод. То есть в отличие от обычного метода экземпляра, который на вход принимает ссылку на конкретный экземпляр, и методы класса, который на вход принимает class, с которым идет работа, статический метод не принимает ничего, только те аргументы, которые в него передают. Используется он для того, когда нам из соображений удобства удобно обращаться к функции в контексте класса. Также мы посмотрели на такой концепт, как property, то есть вычисляемое свойство.