Что такое classmethod в python

Декораторы @classmethod и @staticmethod

Приветствую всех на внеочередном занятии по ООП. Меня часто спрашивают: чем отличаются обычные методы класса от методов, объявленных декораторами:

@classmethod и @staticmethod

Давайте разбираться. На уровне теории это выглядит так. Предположим, у нас есть класс Vector, который содержит два атрибута: MIN_COORD = 0, MAX_COORD = 100; обычный метод setCoords; метод уровня класса: validate и статический метод – norm2:

Что такое classmethod в python. Смотреть фото Что такое classmethod в python. Смотреть картинку Что такое classmethod в python. Картинка про Что такое classmethod в python. Фото Что такое classmethod в python

Так вот, все обычные методы в качестве первого параметра обязательно должны получать ссылку на экземпляр этого класса. И благодаря ей, они могут менять состояние как объекта класса, так и получать доступ к свойствами и методам самого класса Vector.

Когда метод класса объявляется через декоратор @classmethod, то первым параметром ему нужно передать сам класс, а не его экземпляр. В результате, такой метод может обращаться ко всем свойствам и методам текущего класса Vector, но не к экземпляру (из, которого он может быть вызван).

Наконец, третий тип методов, объявленные через декоратор @staticmethod, являются, своего рода, совершенно изолированными и от свойств и методов класса и, уж тем более, от свойств и методов экземпляра. Их можно воспринимать как отдельные, самостоятельные функции, объявленные внутри класса. Обычно, это делают для удобства, т.к. их функционал так или иначе связан с тематикой класса.

Итак, давайте на практике посмотрим, что все это значит. Я объявлю класс Vector вот в таком виде:

И для удобства открою консоль Python, где импортирую этот класс из модуля ex1:

Далее, смотрите, непосредственно через класс Vector можно вызвать метод класса:

Источник

Простое объяснение методов класса, экземпляра класса и статических методов в Python

Хочешь знать больше о Python?

Подпишись на наш канал о Python в Telegram!

Перевод статьи «Python’s Instance, Class, and Static Methods Demystified».

Что такое classmethod в python. Смотреть фото Что такое classmethod в python. Смотреть картинку Что такое classmethod в python. Картинка про Что такое classmethod в python. Фото Что такое classmethod в python

В этой статье я постараюсь объяснить, что стоит за методами класса, статическими методами и обычными методами экземпляра класса.

Если вы сможете достигнуть интуитивного понимания разницы между этими методами, вы также сможете писать объектно-ориентированный код на Python. Такой код проще для понимания, а в долгосрочной перспективе его легче поддерживать.

Обзор статических методов, методов класса и экземпляра класса

Давайте начнем с написания класса (на Python 3), который будет содержать простые примеры методов всех трех видов:

Примечание для пользователей Python 2. Декораторы @staticmethod и @classmethod доступны в Python начиная с версии 2.4, а значит, этот пример тоже будет работать. Вместо использования простого объявления класса class MyClass: вы можете объявить класс нового стиля, который будет наследоваться от object, с синтаксисом class MyClass(object):. Все остальное не требует каких-то уточнений.

Методы экземпляра класса

Первый метод в MyClass, под названием method, это обычный метод экземпляра класса. Это самый базовый вид методов, которым вы будете пользоваться чаще всего. Как видите, этот метод принимает один параметр (self), который при вызове метода указывает на экземпляр MyClass (хотя методы могут принимать и больше одного параметра).

При помощи параметра self методы экземпляра класса могут иметь свободный доступ к атрибутам и другим методам того же объекта. Благодаря этому они на многое способны, когда речь заходит о модификации состояния объекта.

Методы экземпляра также могут иметь доступ к самому классу — при помощи атрибута self.__class__. Это означает, что они могут менять состояние не только объекта, но и класса.

Методы класса

Давайте сравним то, что мы узнали о методах экземпляра класса, со вторым методом — MyClass.classmethod. Я обозначил этот метод при помощи декоратора @classmethod, чтобы было видно, что это метод класса.

Методы класса вместо параметра self принимают параметр cls. Этот параметр при вызове метода указывает не на экземпляр объекта, а на класс.

Поскольку метод класса имеет доступ только к аргументу cls, он не может изменять состояние экземпляра объекта. Для этого нужен доступ к self. Но, тем не менее, методы класса могут изменять состояние класса в целом, что затронет и все экземпляры этого класса.

Статические методы

Третий метод, MyClass.staticmethod, обозначен при помощи декоратора @staticmethod, чтобы показать, что этот метод статический.

Методы такого типа не принимают в качестве параметра ни self, ни cls (хотя, безусловно, они свободно могут принимать другие параметры в любых количествах).

Таким образом, статический метод не может изменять состояние ни объекта, ни класса. Виды данных, которые могут принимать статические методы, ограничены. Эти методы помещаются в класс, просто чтобы они находились в пространстве имен этого класса, т. е., для организационных целей.

Давайте посмотрим, как все это работает!

Пока что все изложенное было чистой теорией. Но я считаю, что вы должны научиться интуитивно улавливать разницу между методами на практике. Сейчас мы разберем несколько более конкретных примеров.

Давайте посмотрим, как все эти методы ведут себя, когда мы их вызываем. Начнем с создания экземпляра класса, а затем вызовем все три метода.

В MyClass реализация каждого метода возвращает сведения, благодаря которым мы можем понимать, к каким частям класса или объекта может иметь доступ метод, а также отслеживать происходящее.

Вот что происходит при вызове метода экземпляра класса:

Мы видим, что method (т. е., метод экземпляра класса) имеет доступ к экземпляру объекта (это видно по выводу ) при помощи аргумента self.

При вызове этого метода Python замещает аргумент self экземпляром объекта (obj). Мы можем проигнорировать синтаксический сахар dot-call синтаксиса (obj.method()) и получить тот же результат, передав экземпляр объекта вручную:

Можете догадаться, что произойдет, если вы попытаетесь вызвать этот метод без первоначального создания экземпляра класса?

Кстати, методы экземпляра класса при помощи атрибута self.__class__ также могут иметь доступ и к самому классу. Это делает данные методы особенно полезными в условиях ограничений доступа: они могут изменять состояние экземпляра объекта и самого класса.

Теперь давайте испытаем метод класса:

Стоит отметить, что при вызове MyClass.classmethod() Python автоматически передает класс в качестве первого аргумента функции. Это поведение Python запускается, если метод вызывается при помощи dot-синтаксиса. В методах экземпляра класса аналогично работает параметр self.

Пожалуйста, обратите внимание, что эти параметры именуются self и cls лишь в силу соглашений. С тем же успехом вы можете назвать их the_object и the_class. Важно то, что они идут первыми в списке параметров метода.

А теперь давайте вызовем статический метод:

Как видите, мы успешно вызвали staticmethod() через объект. Некоторые разработчики удивляются, когда узнают, что можно вызывать статический метод через экземпляр объекта.

Просто когда при вызове статического метода с использованием dot-синтаксиса не передаются аргументы self или cls, Python применяет ограничения доступа.

Этот пример подтверждает, что статические методы не имеют доступа ни к состоянию экземпляра объекта, ни к состоянию класса. Они работают как обычные функции, но при этом относятся к пространству имен класса (и каждого его экземпляра).

Теперь давайте посмотрим, что произойдет, если мы попытаемся вызвать эти методы в самом классе, т. е., без предварительного создания экземпляра объекта:

Этого и следовало ожидать: в этот раз мы не создавали экземпляр объекта и попытались вызвать функцию экземпляра класса прямо из самого класса. Это означает, что у Python не было никакой возможности заполнить аргумент self и, как следствие этого, вызов метода провалился.

Это должно более четко разграничить три вида методов. Но я на этом не остановлюсь. В следующих двух разделах я разберу два немного более реалистичных примера использования разных видов методов.

Мои примеры будут основаны на классе Pizza:

Примечание. В этом примере кода (а также в последующих) для форматирования строки, возвращаемой при помощи __repr__, мы будем использовать Python 3.6 f-strings. В Python 2 и версиях Python 3 до 3.6 для форматирования строки следует использовать другие выражения, например:

Фабрики вкусной пиццы и @classmethod

Наверняка вы знаете, что существует множество вкусных вариантов пиццы:

Итальянцы придумали свои рецепты пиццы столетия назад, так что все они уже имеют какие-то устоявшиеся названия. Мы этим воспользуемся и дадим пользователям нашего класса Pizza лучший интерфейс для создания тех объектов пиццы, о которых они мечтают.

Это можно сделать красиво и чисто, используя методы класса в качестве фабричных функций для разных видов пиццы:

Обратите внимание, что я использую аргумент cls в фабричных методах margherita и prosciutto, а не вызываю конструктор Pizza напрямую.

Вы можете использовать этот прием, чтобы придерживаться принципа DRY (Don’t Repeat Yourself, «Не повторяйся»). Если в какой-то момент мы решим переименовать этот класс, нам не придется обновлять еще и имя конструктора во всех фабричных функциях classmethod.

Что же мы можем сделать при помощи этих фабричных методов? Давайте испытаем их:

Как видите, мы можем использовать фабричные функции для создания новых объектов Pizza в нужной нам конфигурации. Внутри все они используют один конструктор __init__ и по сути просто предоставляют шорткат для запоминания всех возможных ингредиентов.

Можно взглянуть на это применение методов класса и под другим углом: они позволяют вам определить альтернативные конструкторы для ваших классов.

Python допускает только один метод __init__ для каждого класса. Использование методов класса позволяет добавить столько альтернативных конструкторов, сколько нужно. Таким образом вы можете сделать интерфейс ваших классов самодокументированным (в определенной степени) и упростить их использование.

Когда стоит использовать статические методы

Здесь придумать хороший пример немного сложнее. Но знаете что? Я просто продолжу растягивать аналогию с пиццей.

Вот что я придумал:

Что здесь изменилось? Для начала, я изменил конструктор и __repr__, чтобы принимался дополнительный аргумент radius.

Также я добавил метод экземпляра класса area(), который вычисляет и возвращает площадь пиццы (это также хороший кандидат для @property, но пример у нас игрушечный).

Вместо вычисления площади непосредственно в area(), с использованием всем известной формулы площади круга, я вынес его в отдельный статический метод circle_area().

Конечно, этот пример несколько простоват, но он хорошо помогает объяснить некоторые преимущества статических методов.

Как мы уже знаем, статические методы не имеют доступа к состоянию класса или объекта, потому что не принимают аргументы cls или self. Это большое ограничение, но также и отличный сигнал, показывающий, что данный метод ни от чего не зависит.

В приведенном выше примере ясно, что circle_area() никоим образом не может изменять класс или экземпляр класса. (Конечно, это всегда можно обойти при помощи глобальной переменной, но здесь мы не будем это разбирать).

Так в чем же польза?

Когда вы обозначаете метод в качестве статического, это не только подсказывает читателю, что данный метод не будет модифицировать класс или экземпляр класса — это ограничение также применяется средой выполнения Python.

Подобные приемы позволяют четко описывать элементы вашей архитектуры классов. Конечно, эти ограничения можно легко обойти. Но на практике они помогают избежать случайных модификаций, идущих вразрез с оригинальным дизайном.

Другими словами, использование статических методов и методов классов это способ сообщить о намерениях разработчика. Одновременно это способ обеспечить осуществление этих намерений в достаточной мере, чтобы избежать большинства ошибок, которые можно было бы допустить по невнимательности, и багов, которые разрушили бы дизайн.

Написание некоторых из ваших методов подобным образом (нечасто и там, где это имеет смысл) может принести пользу в плане поддерживаемости кода. Также это снижает вероятность того, что другие разработчики используют ваши классы неправильно.

Статические методы также имеют преимущество при тестировании кода.

Поскольку метод circle_area() совершенно не зависит от остального класса, его гораздо проще тестировать. Мы можем это сделать при помощи модульного теста, не беспокоясь об экземпляре класса в целом. То есть, этот метод тестируется, как обычная функция. Опять же, это облегчает поддержку кода в будущем.

Источник

Изучаем Декораторы в Python

Что такое classmethod в python. Смотреть фото Что такое classmethod в python. Смотреть картинку Что такое classmethod в python. Картинка про Что такое classmethod в python. Фото Что такое classmethod в python

Что такое classmethod в python. Смотреть фото Что такое classmethod в python. Смотреть картинку Что такое classmethod в python. Картинка про Что такое classmethod в python. Фото Что такое classmethod в python

Декораторы Python весьма хороши, однако их достаточно сложно понять при первом знакомстве. Декоратор в Python – это функция, которая принимает другую функцию в качестве аргумента. Декоратор модифицирует или улучшает принятую функцию и выдает измененную. Это значит, что когда вы вызываете декорированную функцию, вы получите функцию, которая может иметь небольшие отличия, в виде дополнительных функций, совмещенных с базовым определением. Нам нужно рассмотреть основу декоратора, а именно функцию.

Простая функция

Python Функция это блок кода, который начинается с ключевого слова def, с дальнейшим названием функции. Функция может принимать от нуля и более аргументов, ключевые аргументы или сочетание этих аргументов. Функция всегда выдает результат. Если вы не определили, что именно она должна выдавать, она выдаст None. Вот очень простой пример функции, которая выдает строку:

Все что мы сделали в этом коде, это вызвали функцию и указали значение выдачи. Давайте создадим другую функцию:

Эта функция принимает один аргумент и этот аргумент должен быть функцией или вызываемой. По факту, ее стоит вызывать, используя определенную в прошлом функцию. Вы заметите, что это функция содержит вложенную внутрь функцию, которую мы называем other_func. Она принимает результат переданной функции, её выражение и создает строку, которая говорит нам о том, что мы сделали, после чего она возвращается.

Давайте взглянем на полную версию данного кода:

Так и работает декоратор. Мы создали одну функцию и передали её другой второй функции. Вторая функция является функцией декоратора. Декоратор модифицирует или усиливает функцию, которая была передана и возвращает модификацию. Если вы запустите этот код, вы увидите следующий выход в stdout:

Давайте немного изменим код, чтобы превратить another_function в декоратор:

Обратите внимание на то, что декоратор начинается с символа @, за которым следует название функции, которую мы собираемся «декорировать». Для получения декоратора python, вам нужно только разместить его в строке перед определением функции. Теперь, когда мы вызываем **a_function, она будет декорирована, и мы получим следующий результат:

Давайте создадим декоратор, который будет делать что-нибудь полезное.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Создание логируемого декоратора

Возможно, вам потребуется логировать того, что делает ваша функция. Большую часть времени логинг будет встроен внутри вашей функции. Однако, бывают случаи, когда вам нужно сделать это на уровне функции, что бы получить представление о потоке программы или, возможно, для следования тем или иным условиям бизнеса, таким как аудит. Посмотрим на небольшой декоратор, который мы можем использовать для записи названия любой функции и того, что она делает:

Этот небольшой скрипт содержит функцию log, которая принимает функцию как единственный аргумент. Мы создаем объект логгер, а название лог файла такое же, как и у функции. После этого, функция log будет записывать, как наша функция была вызвана и что она возвращает, если возвращает.

Встроенные декораторы

Python содержит несколько встроенных декораторов. Из всех этих декораторов, самой важной троицей являются:

Также существуют декораторы в различных разделах стандартной библиотеки Python. Одним из примеров является functools.wraps. Мы сосредоточимся на трех главных декораторах, указанных выше.

@classmethod и @staticmethod

Я не пользовался ими ранее, так что сделал небольшое исследование.

Если мы взглянем на пример кода, в котором показано, как работает декоратор, это может помочь понять основные принципы:

Источник

Значение @classmethod и @staticmethod для начинающих?

может кто-нибудь объяснить мне значение @classmethod и @staticmethod в python? Мне нужно знать разницу и смысл.

насколько я понимаю, @classmethod сообщает классу, что это метод, который должен быть унаследован в подклассы или. что-то. Но какой в этом смысл? Почему бы просто не определить метод класса без добавления @classmethod или @staticmethod и @ определения?

tl; dr: , когда должен ли я использовать их,почему должен ли я использовать их, и как должен ли я использовать их?

Я довольно продвинутый с C++, поэтому использование более продвинутых концепций программирования не должно быть проблемой. Не стесняйтесь давать мне соответствующий пример c++, если это возможно.

11 ответов

хотя classmethod и staticmethod очень похожи, есть небольшая разница в использовании для обеих сущностей: classmethod должен иметь ссылку на объект класса в качестве первого параметра, в то время как staticmethod не может иметь параметров.

пример

объяснение

предположим пример класса, занимающегося информацией о дате (это будет наш шаблон):

этот класс, очевидно, может использоваться для хранения информация об определенных датах (без информации о часовом поясе; предположим, что все даты представлены в формате UTC).

Метод Класса

у нас есть некоторые задачи, которые можно красиво сделать с помощью classmethod s.

предположим, что мы хотим создать большое Date экземпляры класса, имеющие информацию о дате, поступающую из внешнего источника, закодированного в виде строки с форматом ‘dd-mm-yyyy’. Предположим, мы должны сделать это в разных местах исходного кода нашего проекта.

Итак, что мы должны сделать вот это:

это будет выглядеть так:

давайте более внимательно рассмотрим вышеуказанную реализацию и рассмотрим, какие преимущества у нас есть здесь:

статический метод

давайте посмотрим на следующий вариант использования.

у нас есть строка даты, которую мы хотим как-то проверить. Эта задача также логически связана с Date класс, который мы использовали до сих пор, но не требует создания экземпляра он.

где staticmethod может быть полезно. Давайте посмотрим на следующий фрагмент кода:

ответ Ростислава Дзинко очень уместен. Я думал, что могу выделить еще одну причину, по которой вы должны выбрать @classmethod над @staticmethod при создании дополнительного конструктора.

в приведенном выше примере, Ростислав используется @classmethod from_string как фабрика для создания Date объекты из других неприемлемых параметров. То же самое можно сделать с @staticmethod как показано в коде ниже:

и new_year и millenium_new_year несколько экземпляров Date класса.

но, если вы внимательно наблюдаете, Заводской процесс жестко закодирован для создания Date объекты независимо от того, что. Это означает, что даже если Date класс подклассов, подклассы по-прежнему будут создавать простые Date object (без какого-либо свойства подкласса). См. это в примере ниже:

в большинстве случаев, это нежелательно. Если вам нужен Заводской метод, который знает класс, который его вызвал, то @classmethod это то, что вам нужно.

переписывание Date.millenium as (это единственная часть вышеуказанного кода, которая изменяется)

причина в том, как вы знаете в настоящее время, @classmethod вместо @staticmethod

@classmethod означает: когда этот метод вызывается, мы передаем класс в качестве первого аргумента, а не экземпляра этого класса (как мы обычно делаем с методами). Это означает, что вы можете использовать класс и его свойства внутри метода, а не конкретного экземпляра.

@staticmethod означает: когда этот метод вызывается, мы не передаем экземпляр класса (как мы обычно делаем с методами). Это означает, что вы можете поместить функцию внутри класса, но не можете получить доступ к экземпляру этот класс (это полезно, когда ваш метод не использует экземпляр).

когда использовать каждый

@staticmethod функция-это не что иное, как функция, определенная внутри класса. Он вызывается без создания экземпляра класса first. Это определение неизменяемо через наследование.

здесь хорошая ссылка на эту тему.

можно было бы использовать @classmethod когда он / она захочет изменить поведение метода, на основе которого подкласс вызывает метод. помните, что у нас есть ссылка на вызывающий класс в методе class.

при использовании static вы хотели бы, чтобы поведение оставалось неизменным в подклассах

небольшая компиляция

@staticmethod Способ записи метода внутри класса без ссылки на вызываемый объект. Поэтому нет необходимости передавать неявный аргумент, такой как self или cls. Он написан точно так же, как написано вне класса, но он не бесполезен в python, потому что, если вам нужно инкапсулировать метод внутри класса, так как этот метод должен быть частью этого класса @staticmethod пригодится в это дело.

@classmethod Это важно, когда вы хотите написать заводской метод и с помощью этого настраиваемого атрибута(ов) может быть присоединен в классе. Этот атрибут(ы) может быть переопределен в унаследованном классе.

сравнение между этими двумя методами может быть ниже

Что такое classmethod в python. Смотреть фото Что такое classmethod в python. Смотреть картинку Что такое classmethod в python. Картинка про Что такое classmethod в python. Фото Что такое classmethod в python

когда я должен их использовать, почему я должен их использовать и как я должен их использовать?

не нужно либо декоратор. Но по принципу, что вы должны минимизировать количество аргументов для функций (см. Clean Coder), они полезны именно для этого.

для обоих методов экземпляра и методы класса, не принимающие хотя бы один аргумент, являются TypeError, но не понимающие семантику этого аргумента-это ошибка пользователя.

(определение some_function ‘s, например:

и это будет работать.)

пунктирные поиски на экземплярах и классах:

Примечание, пунктирный поиск в экземпляре вызывается следующим образом:

и методы вызываются атрибуты:

методы экземпляра

необходимо получить доступ к методам экземпляра из экземпляров класс.

методы класса

вы можете получить доступ к этому методу через экземпляр класса (или подкласса).

статические методы

никакие аргументы не указаны неявно. Этот метод работает как любая функция, определенная (например) в пространстве имен модулей, за исключением того, что ее можно найти

опять же, когда я должен использовать зачем мне их использовать?

каждый из них постепенно становится более ограничительным в информации, которую они передают методу по сравнению с методами экземпляра.

используйте их, когда вам не нужна информация.

это делает ваши функции и методы легче рассуждать и unittest.

функции с меньше аргументов легче рассуждать. Они также легче unittest.

они сродни экземпляру, классу и статическим методам. Имея в виду, что когда у нас есть экземпляр, у нас также есть его класс, снова спросите себя, о чем легче рассуждать?:

примеры строение

вот несколько моих любимых примеров сборки:

на str.maketrans статический метод был функцией в string модуль, но гораздо более удобным для него, чтобы быть доступным от str пространство имен.

на dict.fromkeys метод class возвращает новый словарь, созданный из iterable ключей:

когда подкласс, мы видим, что он получает информацию о классе как метод класса, что очень полезно:

используйте статические методы, когда вам не нужны аргументы класса или экземпляра, но функция связана с использования объекта, и это удобно для функции, чтобы быть в пространстве имен объекта.

используйте методы класса, когда вам не нужна информация об экземпляре, но вам нужна информация о классе, возможно, для другого класса или статических методов или, возможно, для самого конструктора. (Вы не будете жестко кодировать класс, чтобы подклассы могли использоваться здесь.)

Я новичок на этом сайте, я прочитал все ответы выше, и получил информацию, что я хочу. Однако я не имею права голосовать. Поэтому я хочу начать с StackOverflow с ответа, как я его понимаю.

немного другой способ думать об этом, который может быть полезен для кого-то. Метод класса используется в суперклассе для определения того, как этот метод должен вести себя, когда он вызывается различными дочерними классами. Статический метод используется, когда мы хотим вернуть то же самое независимо от дочернего класса, который мы вызываем.

короче говоря, @classmehtod превращает обычный метод в заводской метод.

давайте рассмотрим его на примере:

без @classmethod, вы должны работать, чтобы создавать экземпляры один за другим, и они scartted.

как например с @classmethod

Class метод может изменить состояние класса, он привязан к классу и содержит cls в качестве параметра.

статический метод не может изменить состояние класса, он привязан к классу и не знает class или instance

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *