2016-11-27 5 views
4

Я разработал этот короткий тестовый/примерный код, чтобы лучше понять, как работают статические методы в Python.Какой смысл @staticmethod в Python?

class TestClass: 
    def __init__(self, size): 
     self.size = size 

    def instance(self): 
     print("regular instance method - with 'self'") 

    @staticmethod 
    def static(): 
     print("static instance method - with @staticmethod") 

    def static_class(): 
     print("static class method") 


a = TestClass(1000) 

a.instance() 
a.static() 
TestClass.static_class() 

Этот код работает корректно, он не возвращает никаких ошибок. Мои вопросы:

  1. Правильно ли я понимаю, что «я» можно понимать как нечто вроде «этот метод будет вызван из экземпляра»?

  2. Опять же, в чем логика @staticmethod - это создание статических методов, которые могут быть вызваны из экземпляра? Разве это не так, не Какие статические методы?

  3. Зачем нужен второй подход по сравнению с третьим? (Я предполагаю, что, поскольку декоратор существует, есть точка к этому.) Третий вариант кажется более простым и более простым.

+1

Обратите внимание, что это не будет работать вообще в 2.x, а 'a.static_class()' не будет работать. – jonrsharpe

+1

Добавьте '' TestClass.static() '' и '' a.static_class() '' в свои тестовые примеры и наблюдайте, что происходит. Это может помочь проиллюстрировать, почему «@ staticmethod» является полезным. –

+0

* «Разве это не то, о чем статические методы?» - преимущество того, что можно вызвать его в экземпляре, состоит в том, что 'cls.whatever()' и 'self.whatever()' будут работать правильно, позволяя сохранить имя класса из ваших методов класса и экземпляра и правильно обрабатывать наследование. – jonrsharpe

ответ

3

Это сообщение от static methods. В итоге:

  • метода экземпляр: требуется экземпляр в качестве первого аргумента
  • методы класса: требуется класс в качестве первого аргумента
  • статических методы: не требуют ни в качестве первого аргумента

Что касается ваших вопросов:

  1. Да. Хотя имя переменной self является условным, оно относится к экземпляру.
  2. Статические методы могут использоваться для группировки подобных методов утилиты в одном классе.
  3. Для методов внутри класса вам необходимо либо добавить self в качестве первого аргумента, либо украсить его методом @staticmethod. «Не оформленные методы» без аргументов вызовут ошибку.

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

class TestClass: 

    weight = 200        # class attr 

    def __init__(self, size): 
     self.size = size      # instance attr 

    def instance_mthd(self, val): 
     print("Instance method, with 'self':", self.size*val) 

    @classmethod 
    def class_mthd(cls, val): 
     print("Class method, with `cls`:", cls.weight*val) 

    @staticmethod 
    def static_mthd(val): 
     print("Static method, with neither args:", val) 

a = TestClass(1000) 

a.instance_mthd(2) 
# Instance method, with 'self': 2000 

TestClass.class_mthd(2) 
# Class method, with `cls`: 400 

a.static_mthd(2) 
# Static method, with neither args: 2 

В целом, вы можете думать о каждом методе в терминах доступа:

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

Обратите внимание в приведенном выше примере, то же аргумент передается для каждого типа метода, но доступ к атрибутам экземпляра и класса различаются по self и cls соответственно.

Обратите внимание, есть способ доступа к компонентам класса метода экземпляра с помощью self.__class__, тем самым устраняя необходимость метода класса:

... 

    def instance_mthd2(self, val): 
     print("Instance method, with class access via `self`:", self.__class__.weight*val) 
    ... 

a.instance_mthd2(2) 
# Instance method, with class access via `self`: 400 

REF: Я рекомендую смотреть talkразвития Раймонда Hettinger в класс Питона Инструментарий, который четко разъясняет цель каждого типа метода примерами.

+0

Is static_class() из моего примера, что вы определяете как метод класса? – rbrtk

+1

Не совсем. Украсьте '@ classmethod' и передайте' cls' в качестве первого аргумента. Тогда это будет метод класса. – pylang

1

Вот ответы на ваш вопрос:

Вопрос 1:

Правильно ли я понимаю, что «я» можно понимать как что-то вроде «этот метод будет вызываться из экземпляра «?

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

def my_class_function(self) 

можно назвать как:

self.my_class_function() 
OR, 
my_class_function(self) 

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

Вопрос 2:

Затем снова, что логика @staticmethod - это создать статические методы, которые могут быть вызваны из экземпляра? Разве это не то, что статические методы?

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

Вопрос 3:

Почему бы второй подход отдавать предпочтение перед третьей? (Я предполагаю, что, поскольку декоратор существует, есть точка к этому.) Третий вариант кажется более простым и более простым.

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

1

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

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

Третий вариант, статические методы, является странным человеком. Они не проходят ни экземпляр, ни класс. Они полезны для использования функций утилиты в структуре класса программы для организационных целей, но так, что они четко сигнализируют (для проверки кода, «линтинга» и инструментов проверки программ и т. Д.), Что вы намеренно не зависите от экземпляра или класса значения. Таким образом, вы не получите предупреждения о «переменных, объявленных, но никогда не используемых» об этом неиспользованном self.

С точки зрения звонящего, статические методы выглядят как любой другой вызов метода. Если у вас не было @staticmethod, вы можете просто использовать обычный метод экземпляра или класса (хотя и с риском избыточной переменной, не используемой!) Linter warnings). Поэтому, в отличие от методов класса, статические методы являются полностью необязательной частью Python. Они не добавляют никакой функциональности к языку; вместо этого они дают возможность сделать намерения разработчика более четкими.