В чем разница между следующими методами класса?
Это то, что одно статично, а другое нет?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
@classmethod
к определению. Первый параметр должен вызыватьсяcls
вместоself
и будет получать объект класса, а не экземпляр вашего класса:Test.method_three()
иa_test.method_three()
эквивалентны.self
аргумента? Есть ли сильный вариант использования для этого?Ответы:
В Python существует различие между связанными и несвязанными методами.
По сути, вызов функции-члена (например
method_one
), связанной функциипереводится на
т.е. вызов несвязанного метода. Из-за этого вызов вашей версии
method_two
не удастся сTypeError
Вы можете изменить поведение метода, используя декоратор
Декоратор говорит встроенному метаклассу по умолчанию
type
(класс класса, см. Этот вопрос ) не создавать связанные методы дляmethod_two
.Теперь вы можете вызывать статический метод как для экземпляра, так и для класса напрямую:
источник
Методы в Python - очень и очень простая вещь, когда вы понимаете основы системы дескрипторов. Представьте себе следующий класс:
Теперь давайте посмотрим на этот класс в оболочке:
Как вы можете видеть, если вы получите доступ к
foo
атрибуту класса, вы получите несвязанный метод, однако внутри хранилища классов (dict) есть функция. Почему это? Причина этого в том, что класс вашего класса реализует__getattribute__
дескрипторы. Звучит сложно, но это не так.C.foo
примерно эквивалентно этому коду в этом особом случае:Это потому, что у функций есть
__get__
метод, который делает их дескрипторами. Если у вас есть экземпляр класса, он почти такой же, просто этоNone
экземпляр класса:Теперь, почему Python делает это? Потому что объект метода привязывает первый параметр функции к экземпляру класса. Вот откуда приходит я. Теперь иногда вы не хотите, чтобы ваш класс сделал функцию методом, вот где
staticmethod
вступает в игру:staticmethod
Декоратор оборачивает свой класс и реализует манекен ,__get__
который возвращает обернутую функцию как функция , а не как метод:Надеюсь, это все объясняет.
источник
staticmethod
Декоратор оборачивает ваш класс (...) Эта фраза немного вводит в заблуждение , как класс , который обертывают класс от метода ,foo
а не класс , в которомfoo
определен.Когда вы вызываете члена класса, Python автоматически использует ссылку на объект в качестве первого параметра. Переменная на
self
самом деле ничего не значит, это просто соглашение о кодировании. Вы можете позвонить,gargaloo
если хотите. Тем не менее, вызов tomethod_two
вызовет aTypeError
, потому что Python автоматически пытается передать параметр (ссылку на его родительский объект) в метод, который был определен как не имеющий параметров.Чтобы действительно заставить это работать, вы можете добавить это к определению вашего класса:
или вы можете использовать
@staticmethod
функцию декоратор .источник
источник
Class.instance_method() # The class cannot use an instance method
это можно использовать. Просто передайте экземпляр вручную:Class.instance_method(a)
TyeError
линии.a.class_method()
, кажется,a.c
что обновился до1
, поэтому вызовClass.class_method()
, обновилClass.c
переменную до2
. Однако, когда вы назначилиa.c=5
, почему неClass.c
обновились до5
?method_two не будет работать, потому что вы определяете функцию-член, но не сообщаете ей, из чего состоит функция. Если вы выполните последнюю строку, вы получите:
Если вы определяете функции-члены для класса, первым аргументом всегда должно быть «self».
источник
Точное объяснение от Армина Ронахера выше, расширяя его ответы, чтобы новички вроде меня хорошо поняли:
Разница в методах, определенных в классе, будь то статический метод или метод экземпляра (есть еще один тип - метод класса - здесь не обсуждается, поэтому его пропускают), заключается в том, связаны ли они каким-либо образом с экземпляром класса или нет. Например, скажите, получает ли метод ссылку на экземпляр класса во время выполнения
Свойство
__dict__
словаря объекта класса содержит ссылку на все свойства и методы объекта класса и, таким образом,метод foo доступен, как указано выше. Здесь важно отметить, что все в python является объектом, и поэтому ссылки в словаре выше сами указывают на другие объекты. Позвольте мне назвать их Объектами Свойств Класса - или как CPO в рамках моего ответа для краткости.
Если CPO является дескриптором, то интерпретатор python вызывает
__get__()
метод CPO для доступа к значению, которое он содержит.Чтобы определить, является ли CPO дескриптором, интерпретатор python проверяет, реализует ли он протокол дескриптора. Для реализации дескриптора протокола необходимо реализовать 3 метода
например
где
self
является CPO (это может быть экземпляр списка, str, функции и т. д.) и предоставляется средой выполненияinstance
является экземпляром класса, в котором определен этот CPO (объект 'c' выше), и он должен быть предоставлен нами для простотыowner
это класс, где этот CPO определен (объект класса 'C' выше) и должен быть предоставлен нами. Однако это потому, что мы называем это в СРО. когда мы вызываем его в экземпляре, нам не нужно указывать его, поскольку среда выполнения может предоставить экземпляр или его класс (полиморфизм)value
является предполагаемым значением для CPO и должно быть предоставлено намиНе все CPO являются дескрипторами. Например
Это потому, что класс списка не реализует протокол дескриптора.
Таким образом, аргумент self in
c.foo(self)
необходим, потому что его сигнатура метода на самом деле таковаC.__dict__['foo'].__get__(c, C)
(как объяснено выше, C не нужен, так как его можно обнаружить или преобразовать). Именно поэтому вы получаете TypeError, если вы не передаете требуемый аргумент экземпляра.Если вы заметили, что на метод все еще ссылаются через класс Object C, и связывание с экземпляром класса достигается посредством передачи контекста в форме объекта экземпляра в эту функцию.
Это довольно круто, поскольку, если вы решили не сохранять контекст или не привязываться к экземпляру, все, что нужно, - это написать класс, чтобы обернуть дескриптор CPO и переопределить его
__get__()
метод, не требуя контекста. Этот новый класс является тем, что мы называем декоратором, и применяется через ключевое слово@staticmethod
Отсутствие контекста в новом обернутом CPO
foo
не приводит к ошибке и может быть проверено следующим образом:Вариант использования статического метода - это скорее пространство имен и возможность сопровождения кода (удаление его из класса и обеспечение его доступности в модуле и т. Д.).
Возможно, лучше по возможности писать статические методы, а не методы экземпляра, если, конечно, вам не нужно контекстуализировать методы (такие как переменные экземпляра доступа, переменные класса и т. Д.). Одна из причин - облегчить сборку мусора, не сохраняя ненужные ссылки на объекты.
источник
это ошибка.
во-первых, первая строка должна быть такой (будьте осторожны с заглавными буквами)
Каждый раз, когда вы вызываете метод класса, он получает себя в качестве первого аргумента (отсюда и имя self), и method_two выдает эту ошибку
источник
Второй не будет работать, потому что, когда вы вызываете его так, что Python внутренне пытается вызвать его с экземпляром a_test в качестве первого аргумента, но ваш method_two не принимает никаких аргументов, поэтому он не будет работать, вы получите время выполнения ошибка. Если вам нужен эквивалент статического метода, вы можете использовать метод класса. Методы классов в Python гораздо меньше, чем статические методы в таких языках, как Java или C #. Чаще всего лучшим решением является использование метода в модуле, вне определения класса, который работает более эффективно, чем методы класса.
источник
Class Test(object): @staticmethod def method_two(): print(“called method_two”)
Один вариант использования, о котором я думал, это когда вы хотите, чтобы функция была частью класса, но не хотите, чтобы пользователь обращался к функции напрямую. Таким образом, онmethod_two
может вызываться другими функциями внутриTest
экземпляра, но не может вызываться с помощьюa_test.method_two()
. Если я используюdef method_two()
, будет ли это работать для этого варианта использования? Или есть лучший способ изменить определение функции, чтобы она работала так, как предназначено для приведенного выше варианта использования?Вызов method_two вызовет исключение для того, чтобы не принять параметр self, который среда выполнения Python автоматически пропустит.
Если вы хотите создать статический метод в классе Python, украсьте его с помощью
staticmethod decorator
.источник
Пожалуйста, прочитайте эту документацию из Первого класса Гвидо обо всем. Ясно объяснил, как рождаются несвязанные, связанные методы.
источник
Определение
method_two
недействительно. Когда вы позвонитеmethod_two
, вы получитеTypeError: method_two() takes 0 positional arguments but 1 was given
от переводчика.Метод экземпляра - это ограниченная функция, когда вы вызываете ее следующим образом
a_test.method_two()
. Он автоматически принимаетself
, что указывает на экземплярTest
, в качестве первого параметра. С помощьюself
параметра метод экземпляра может свободно обращаться к атрибутам и изменять их для одного и того же объекта.источник
Несвязанные методы
Несвязанные методы - это методы, которые еще не связаны ни с одним конкретным экземпляром класса.
Связанные методы
Связанные методы - это те, которые связаны с конкретным экземпляром класса.
Как описано здесь , self может ссылаться на разные вещи в зависимости от того, связана ли функция, не связана или статична.
Посмотрите на следующий пример:
Поскольку мы не использовали экземпляр класса -
obj
при последнем вызове, мы можем сказать, что он выглядит как статический метод.Если так, в чем разница между
MyClass.some_method(10)
вызовом и вызовом статической функции, декорированной@staticmethod
декоратором?Используя декоратор, мы явно даем понять, что метод будет использоваться без предварительного создания экземпляра для него. Обычно не следует ожидать, что методы члена класса будут использоваться без экземпляра, и доступ к ним может вызвать возможные ошибки в зависимости от структуры метода.
Кроме того, добавляя
@staticmethod
декоратор, мы делаем возможным доступ через объект.Вы не можете сделать приведенный выше пример с методами экземпляра. Вы можете пережить первый (как мы делали раньше), но второй будет переведен в несвязанный вызов,
MyClass.some_method(obj, 10)
который вызовет a,TypeError
поскольку метод экземпляра принимает один аргумент, а вы непреднамеренно пытались передать два.Затем вы можете сказать: «Если я могу вызывать статические методы как через экземпляр, так и через класс,
MyClass.some_static_method
и этоMyClass().some_static_method
должны быть одни и те же методы». Да!источник
Связанный метод = метод экземпляра
Несвязанный метод = статический метод.
источник