classmethod
и staticmethod
являются дескрипторы, и ни один из них делают то, что вы ожидаете, а не только staticmethod
.
При доступе к A.one
, это создает связанный метод на A
, затем сделать что атрибут B
, а потому, что это связано с A
, то cls
аргумент всегда будет A
, даже если вы звоните B.one
(это так как на Python 2, так и на Python 3, везде это не так).
При доступе к A.two
, этому возвращению необработанного объекта функции (staticmethod
дескриптору не нужно делать ничего особенного в стороне от предотвращения связывания, которая будет проходить self
или cls
, поэтому он просто возвращает то, что она обернута). Но этот необработанный объект-объект затем привязывается к B
как к способу несвязанного экземпляра, потому что без обертки staticmethod
это точно так же, как вы определили его как обычно.
Причина, по которой последний работает в Python 3, заключается в том, что Python 3 не имеет понятия о несвязанных методах. Он имеет функции (которые при доступе через экземпляр класса становятся связанными методами) и связанными методами, где Python 2 имеет функции, несвязанные методы и связанные методы.
Unbound methods проверяет, что они вызываются с объектом соответствующего типа, таким образом, ваша ошибка. Обычные функции просто требуют правильного количества аргументов.
Декоратор staticmethod
в Python 3 все еще возвращает исходный объект функции, но в Python 3 это нормально; так как это не специальный объект unbound method, если вы вызываете его на самом классе, это просто как функция с именами, а не какой-либо метод.Вы бы увидели проблему, если вы пытались сделать:
B().two()
, хотя, потому что это сделает связанный метод из этого экземпляра B
и функции two
, передавая дополнительный аргумент (self
), что two
не делает принимаем. В принципе, на Python 3, staticmethod
- это удобство, позволяющая вам вызывать функцию на экземплярах без необходимости связывания, но если вы только когда-либо вызываете функцию, ссылаясь на сам класс, это не нужно, потому что это просто простая функция, а не Python 2 "несвязанный метод".
Если у вас есть причина для выполнения этой копии (как правило, я предлагаю наследовать от A
, но что бы то ни было), и вы хотите удостовериться, что вы получили дескриптор завернутой версии функции, а не то, что дескриптор дает вам при доступе на A
, вы бы обойти протокол дескриптора путем прямого доступа к A
«ы __dict__
:
class B(object):
one = A.__dict__['one']
two = A.__dict__['two']
Прямого копирования из словаря класса, магический протокол дескриптора никогда не вызываются, и вы получите staticmethod
и classmethod
завернутые версии one
и two
.
Большое спасибо за информативный ответ! Вариант использования - это тестовый набор: https://github.com/al4/python-checkrunner/blob/master/tests/test_checkrunner.py. Я хотел повторно использовать функции и сгруппировать их в класс, чтобы не допустить, чтобы PyCharm жаловался на применение декораторы вне класса. Я думаю, лучший подход - это вручную вызвать staticmethod с классом «sub». –
@AlexForbes: В этом случае я бы реализовал класс общих функций и использовал его как mixin в классах, которые в них нуждаются. 'class CommonTests (object): ... define one, two ...', а затем смешивать его через множественное наследование: 'class A (unittests.TestCase, CommonTests): ... Специальные тесты ...', затем 'class B (unittests.TestCase, CommonTests): ... B конкретные тесты ...'. Теперь все методы CommonTests автоматически наследуются в 'A' и' B' без необходимости назначать их по имени индивидуально. Класс mixin не наследуется от 'TestCase', поэтому он не будет протестирован сам по себе. – ShadowRanger