Почему мы не можем "самоплатить" в метод?

>>> class Potato(object):
...     def method(self, spam):
...         print self, spam
... 
>>> spud = Potato()

Работает:

>>> Potato.method(spud, **{'spam': 123})
<__main__.Potato object at 0x7f86cd4ee9d0> 123

Не работает:

>>> Potato.method(**{'self': spud, 'spam': 123})
# TypeError

Но почему нет? Я думал, что "я" был просто конвенцией, и в этом аргументе не было ничего особенного?

Ответ 1

Объект-оболочка Python 2 instancemethod настаивает на проверке первого позиционного аргумента и эта проверка не поддерживает аргументы ключевого слова, полная остановка:

>>> Potato.method(self=spud, spam=123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method method() must be called with Potato instance as first argument (got nothing instead)

Обратите внимание, что я не использовал распаковку аргументов там!

Вы можете использовать позиционные аргументы просто:

>>> Potato.method(*(spud,), **{'spam': 123})
<__main__.Potato object at 0x1002b57d0> 123

или вы можете получить доступ к исходному объекту функции:

>>> Potato.method.__func__(**{'self': spud, 'spam': 123})
<__main__.Potato object at 0x1002b57d0> 123

чтобы обойти это ограничение.

Python 3 больше не использует оболочку метода для несвязанных методов; основная функция возвращается непосредственно.