Python - уникальный язык в том смысле, что его довольно легко выучить,
учитывая его простой синтаксис, но при этом он чрезвычайно мощный. Под
капотом гораздо больше функций, чем вы можете себе представить. Хотя в
этом утверждении я мог бы иметь в виду довольно много разных вещей, в
данном случае я говорю о
декораторах
@classmethod
и @staticmethod
. Для многих ваших проектов вам,
вероятно, не нужны эти функции и вы не сталкивались с ними, но вы можете
обнаружить, что они пригодятся гораздо больше, чем вы ожидаете. Не так
очевидно, как создавать статические методы Python, и здесь на помощь
приходят эти два декоратора.
В этой статье я расскажу вам, что делает каждый из этих декораторов, их отличия и несколько примеров каждого из них.
Декоратор @classmethod
Этот декоратор существует, поэтому вы можете создавать методы класса,
которым передается фактический объект класса в вызове функции, так же,
как self
передается любому другому обычному методу экземпляра в
классе.
В этих методах экземпляра self
- это сам объект экземпляра класса,
который затем может использоваться для обработки данных экземпляра.
@classmethod
также имеют обязательный первый аргумент, но этот
аргумент не является экземпляром класса, это фактически сам
неустановленный класс. Итак, хотя типичный метод класса может выглядеть
так:
class Student(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
scott = Student('Scott', 'Robinson')
@classmethod
этого можно использовать аналогичный метод @classmethod:
class Student(object):
@classmethod
def from_string(cls, name_str):
first_name, last_name = map(str, name_str.split(' '))
student = cls(first_name, last_name)
return student
scott = Student.from_string('Scott Robinson')
Это очень хорошо следует статическому шаблону фабрики , инкапсулируя логику синтаксического анализа внутри самого метода.
Приведенный выше пример очень простой, но вы можете представить более
сложные примеры, которые сделают его более привлекательным. Представьте,
что Student
можно сериализовать во многих различных форматах. Вы
можете использовать ту же стратегию, чтобы проанализировать их все:
class Student(object):
@classmethod
def from_string(cls, name_str):
first_name, last_name = map(str, name_str.split(' '))
student = cls(first_name, last_name)
return student
@classmethod
def from_json(cls, json_obj):
# parse json...
return student
@classmethod
def from_pickle(cls, pickle_file):
# load pickle file...
return student
Декоратор становится еще более полезным, когда вы понимаете его
полезность в подклассах. Поскольку объект класса предоставляется вам
внутри метода, вы все равно можете использовать тот же @classmethod
для подклассов.
Декоратор @staticmethod
@staticmethod
похож на @classmethod
в том, что он может быть вызван
из неустановленного объекта класса, хотя в этом случае его методу cls
Пример может выглядеть так:
class Student(object):
@staticmethod
def is_full_name(name_str):
names = name_str.split(' ')
return len(names) > 1
Student.is_full_name('Scott Robinson') # True
Student.is_full_name('Scott') # False
Поскольку self
не передается, это означает, что у нас также нет
доступа к каким-либо данным экземпляра, и, следовательно, этот метод
также не может быть вызван для созданного объекта.
Эти типы методов обычно не предназначены для создания / инстанцирования объектов, но они могут содержать некоторый тип логики, относящийся к самому классу, например вспомогательный или служебный метод.
@classmethod против @staticmethod
Самым очевидным отличием этих декораторов является их способность
создавать статические методы внутри класса. Эти типы методов могут
вызываться для неустановленных объектов класса, подобно классам,
использующим static
в Java.
На самом деле между этими двумя декораторами методов есть только одно
различие, но оно очень важное. Вы, наверное, заметили в разделах выше,
что методы @classmethod
cls
отправляемый их методам, а
@staticmethod
- нет.
Этот cls
- это объект класса, о котором мы говорили, который позволяет
@classmethod
легко создавать экземпляры класса независимо от
происходящего наследования. Отсутствие этого параметра cls
@staticmethod
делает их настоящими статическими методами в
традиционном смысле. Их основная цель - содержать логику, относящуюся к
классу, но эта логика не должна нуждаться в конкретных данных экземпляра
класса.
Более длинный пример
Теперь давайте посмотрим на другой пример, в котором мы используем оба типа вместе в одном классе:
# static.py
class ClassGrades:
def __init__(self, grades):
self.grades = grades
@classmethod
def from_csv(cls, grade_csv_str):
grades = map(int, grade_csv_str.split(', '))
cls.validate(grades)
return cls(grades)
@staticmethod
def validate(grades):
for g in grades:
if g < 0 or g > 100:
raise Exception()
try:
# Try out some valid grades
class_grades_valid = ClassGrades.from_csv('90, 80, 85, 94, 70')
print 'Got grades:', class_grades_valid.grades
# Should fail with invalid grades
class_grades_invalid = ClassGrades.from_csv('92, -15, 99, 101, 77, 65, 100')
print class_grades_invalid.grades
except:
print 'Invalid!'
$ python static.py
Got grades: [90, 80, 85, 94, 70]
Invalid!
Обратите внимание, как статические методы могут даже работать вместе с
вызовом from_csv
validate
с использованием объекта cls
При
выполнении приведенного выше кода должен быть распечатан массив
действительных оценок, а со второй попытки произойдет сбой, в результате
чего будет выведено «Недействительно!».
Заключение
В этой статье вы увидели, как @classmethod
и @staticmethod
работают
в Python, некоторые примеры каждого из них в действии и чем они
отличаются друг от друга. Надеюсь, теперь вы можете применить их к своим
собственным проектам и использовать их для дальнейшего улучшения
качества и организации вашего собственного кода.
Вы когда-нибудь использовали эти декораторы раньше, и если да, то как? Дайте нам знать об этом в комментариях!