Объяснение @classmethod и @staticmethod Python

Python - уникальный язык в том смысле, что его довольно легко выучить, учитывая его простой синтаксис, но при этом он чрезвычайно мощный. Под капотом гораздо больше функций, чем вы можете себе представить. Хотя в этом утверждении я мог бы иметь в виду довольно много разных вещей, в данном случае я говорю о декораторах [https://wiki.python.org/moin/PythonDecorators] @classmethod и @staticmethod. Для многих ваших проектов вам, вероятно, не понадобились или вы не сталкивались с этими функциями, но вы можете

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, некоторые примеры каждого из них в действии и чем они отличаются друг от друга. Надеюсь, теперь вы можете применить их к своим собственным проектам и использовать их для дальнейшего улучшения качества и организации вашего собственного кода.

Вы когда-нибудь использовали эти декораторы раньше, и если да, то как? Дайте нам знать об этом в комментариях!

comments powered by Disqus