Staticmethod python что это
Перейти к содержимому

Staticmethod python что это

  • автор:

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

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

Однако в случае классов, когда метод применяется к объекту, этот экземпляр передается в метод в качестве первого аргумента:

>>> class A: . def meth(self): . print('meth') . >>> a = A() >>> a.meth() meth >>> A.meth(a) meth

Вызов a.meth() на самом деле преобразуется к A.meth(a) , то есть мы идем к «модулю A» и в его пространстве имен ищем атрибут meth . Там оказывается, что meth это функция, принимающая один обязательный аргумент. Тогда ничего не мешает сделать так:

>>> b = 10 >>> A.meth(b) meth

В таком «модульном формате» вызова методов передавать объект-экземпляр именно класса A совсем не обязательно. Однако нельзя сделать так:

>>> b = 10 >>> b.meth() Traceback (most recent call last): File "", line 1, in AttributeError: 'int' object has no attribute 'meth'

Если объект передается методу в нотации через точку, то этот метод должен быть описан в том классе, которому принадлежит объект, или в родительских классах. В данном случае у класса int нет метода meth . Объект b классу A не принадлежит. Поэтому интерпретатор никогда не найдет метод meth .

Что делать, если возникает необходимость в методе, который бы не принимал объект данного класса в качестве аргумента? Да, мы можем объявить метод вообще без параметров и вызывать его только через класс:

>>> class A: . def meth(): . print('meth') . >>> A.meth() meth >>> a = A() >>> a.meth() Traceback (most recent call last): File "", line 1, in TypeError: meth() takes 0 positional arguments but 1 was given

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

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

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

Однако в Python тоже можно реализовать подобное, то есть статические методы, с помощью декоратора @staticmethod :

>>> class A: . @staticmethod . def meth(): . print('meth') . >>> a = A() >>> a.meth() meth >>> A.meth() meth

Пример с параметром:

>>> class A: . @staticmethod . def meth(value): . print(value) . >>> a = A() >>> a.meth(1) 1 >>> A.meth('hello') hello

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

Особенности статических методов в Python

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

from math import pi class Cylinder: @staticmethod def make_area(d, h): circle = pi * d ** 2 / 4 side = pi * d * h return round(circle*2 + side, 2) def __init__(self, di, hi): self.dia = diameter self.h = high self.area = self.make_area(di, hi) a = Cylinder(1, 2) print(a.area) print(a.make_area(2, 2))

В примере вызов make_area() за пределами класса возможен в том числе через экземпляр. При этом свойство area самого объекта a не меняется. Мы просто вызываем функцию, находящуюся в пространстве имен класса.

Практическая работа

Приведенный в конце урока пример плохой. Мы можем менять значения полей dia и h объекта за пределами класса простым присваиванием (например, a.dia = 10 ). При этом площадь никак не будет пересчитываться. Также мы можем назначить новое значение для площади, как простым присваиванием, так и вызовом функции make_area() с последующим присваиванием. Например, a.area = a.make_area(2, 3) . При этом не меняются высота и диаметр.

Защитите код от возможных логических ошибок следующим образом:

  • Свойствам dia и h объекта по-прежнему можно выполнять присваивание за пределами класса. Однако при этом «за кулисами» происходит пересчет площади, то есть изменение значения area .
  • Свойству area нельзя присваивать за пределами класса. Можно только получать его значение.

Подсказка: вспомните про метод __setattr__ .

Курс с примерами решений практических работ:
pdf-версия

X Скрыть Наверх

Объектно-ориентированное программирование на Python

Декоратор staticmethod#

Статический метод — это метод, который не привязан к состоянию экземпляра или класса. Для создания статического метода используется декоратор staticmethod.

Преимущества использования staticmethod:

  • Это подсказка для тех, кто читает код, которая указывает на то, что метод не зависит от состояния экземпляра класса.

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

import time from textfsm import clitable from base_ssh import BaseSSH class CiscoSSH(BaseSSH): def __init__(self, ip, username, password, enable_password, disable_paging=True): super().__init__(ip, username, password) self._ssh.send('enable\n') self._ssh.send(enable_password + '\n') if disable_paging: self._ssh.send('terminal length 0\n') time.sleep(1) self._ssh.recv(self._MAX_READ) self._mgmt_ip = None @staticmethod def _parse_show(command, command_output, index_file='index', templates='templates'): attributes = 'Command': command, 'Vendor': 'cisco_ios'> cli_table = clitable.CliTable(index_file, templates) cli_table.ParseCmd(command_output, attributes) return [dict(zip(cli_table.header, row)) for row in cli_table] def send_show_command(self, command, parse=True): command_output = super().send_show_command(command) if not parse: return command_output return self._parse_show(command, command_output) 
In [6]: r1 = CiscoSSH('192.168.100.1', 'cisco', 'cisco', 'cisco') In [7]: r1.send_show_command('sh ip int br') Out[7]: ['intf': 'Ethernet0/0', 'address': '192.168.100.1', 'status': 'up', 'protocol': 'up'>, 'intf': 'Ethernet0/1', 'address': '192.168.200.1', 'status': 'up', 'protocol': 'up'>, 'intf': 'Ethernet0/2', 'address': '19.1.1.1', 'status': 'up', 'protocol': 'up'>, 'intf': 'Ethernet0/3', 'address': '192.168.230.1', 'status': 'up', 'protocol': 'up'>, 'intf': 'Loopback0', 'address': '10.4.4.4', 'status': 'up', 'protocol': 'up'>, 'intf': 'Loopback90', 'address': '90.1.1.1', 'status': 'up', 'protocol': 'up'>] 

Зачем в питоне нужен @staticmethod

Есть класс printer . У него есть 2 метода, делающие одно и то же. Различие в том, что один из методов — с декоратором @staticmethod , а другой — без. Но я могу вызывать оба метода без создания экземпляра класса.

class printer(): ''' Тест @staticmethod ''' def not_static_print(self, text = 'Example Text'): print(text) @staticmethod def static_print(text = 'Example Text'): print(text) # Не создаю никаких экземпляров printer.not_static_print(None, 'Emm?') printer.static_print('Something like this.') 

Просто для not_static_print() я указываю экземпляр, а точнее его отсутствие ( None ) Есть ли принципиальная разница в использовании этих методов?

Отслеживать
149k 12 12 золотых знаков 59 59 серебряных знаков 132 132 бронзовых знака
задан 6 авг 2018 в 17:19
Don2Quixote Don2Quixote
1,705 3 3 золотых знака 12 12 серебряных знаков 26 26 бронзовых знаков

p = printer() p.not_static_print(None, ‘Emm?’) а теперь попробуйте вызвать тот not_static_print с None первым аргументом 🙂

6 авг 2018 в 17:29

кст, в вашем примере у класса нет полей объекта и в not_static_print вы к ним не обращайтесь, а это будет возможно только через self , но если вы это сделайте и передадите None , то будет ошибка AttributeError: ‘NoneType’ object has no attribute . Вот для таких случаев и существуют статичные методы — они не могут работать с полями и методами объекта, но при этом их не сделали просто функциями, т.к. они логически относятся к данному классу / типу

Разница между @staticmethod и @classmethod в Python

Python @classmethod означает, что при вызове этого метода мы передаем класс как первый аргумент вместо экземпляра этого класса («self»). Функция @classmethod также может быть вызвана без создания экземпляра класса, но ее определение следует подкласс Sub, а не родительский класс, через наследование, может быть переопределено подклассом. Это потому, что первым аргументом для функции @classmethod всегда должен быть cls (класс). Кроме того, @classmethod важен, когда вы хотите написать фабричный метод, и этот пользовательский атрибут может быть прикреплен в классе. Этот атрибут (ы) может быть переопределен в унаследованном классе.

@classmethod def some_class_method(cls, *args, **kwds): pass

Статический метод — это метод, который ничего не знает о классе или экземпляре, на который он был вызван. @staticmethod означает, что когда этот метод вызывается, мы не передаем ему экземпляр класса. Это означает, что нет необходимости передавать неявный аргумент, например self или cls. Он может быть вызван без создания экземпляра класса. Это определение неизменно через наследование. В Python это бесполезно, потому что вы можете просто использовать функцию модуля вместо staticmethod.

@staticmethod def some_static_method(*args, **kwds): pass

(5 оценок, среднее: 4,00 из 5)

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

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