Рубрики
Без рубрики

Python’s @classmethod и @staticmethod Объяснили

Автор оригинала: Scott Robinson.

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 :

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')

Это очень хорошо соответствует шаблону static factory pattern , инкапсулируя логику синтаксического анализа внутри самого метода.

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

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