Мне нравится просматривать это поведение с «снизу вверх».
Функция в Python действует как «descriptor object». Таким образом, он имеет метод __get__()
.
Доступ к атрибуту класса, который имеет такой метод __get__()
, «перенаправлен» на этот метод. Атрибут доступа к классу выполняется как attribute.__get__(None, containing_class)
, в то время как доступ к экземпляру атрибута сопоставляется с attribute.__get__(instance, containing_class)
.
Задача функции __get__()
функции заключается в том, чтобы обернуть функцию в объект метода, который обертывает параметр self
- для случая доступа атрибута к экземпляру. Это называется связанным методом.
В отношении атрибута класса на 2.x функция __get__()
возвращает возвращенную оболочку метода, тогда как, как I learned today, на 3.x, она возвращается сама. (Обратите внимание, что механизм __get__()
все еще существует в 3.x, но функция просто возвращает себя.) Это почти то же самое, если вы посмотрите, как он вызывается, но оболочка unbound-метода дополнительно проверяет правильный тип аргумента self
.
A staticmethod()
вызов просто создает объект, вызов которого __get__()
предназначен для возврата первоначально заданного объекта, чтобы он не отклонил описанное поведение. Вот как работает HYRY's trick: атрибут acces отменяет обертку staticmethod()
, вызов делает это снова, так что атрибут «новый» имеет тот же статус, что и старый, хотя в этом случае staticmethod()
, кажется, применяется дважды (но на самом деле isn ' т).
(BTW: Это работает даже в этом странном контексте:.
s = staticmethod(8)
t = s.__get__(None, 2) # gives 8
хотя 8
не является функцией и 2
не класс)
В вашем вопросе, у вас есть две ситуации:
cmd = Cmd.cmdOne
cmd() # works fine
обращается к классу и просит его атрибута cmdOne
, в staticmethod()
объекта. Это запрашивается через его __get__()
и возвращает исходную функцию, которая затем вызывается. Вот почему он отлично работает.
Cmd.cmd = Cmd.cmdOne
Cmd.cmd() # unbound error
делает то же самое, но затем присваивает эту функцию Cmd.cmd
. Следующая строка - это доступ к атрибуту, который также вызывает вызов __get__()
самой функции и, таким образом, возвращает несвязанный метод, который должен быть вызван с правильным объектом self
в качестве первого аргумента.
Не отвечает на вопрос. – martineau