Почему я не могу передать себя в качестве именованного аргумента методу экземпляра в Python? - PullRequest
5 голосов
/ 14 марта 2010

Это работает:

>>> def bar(x, y):
...     print x, y
...
>>> bar(y=3, x=1)
1 3

И это работает:

>>> class Foo(object):
...     def bar(self, x, y):
...             print x, y
...
>>> z = Foo()
>>> z.bar(y=3, x=1)
1 3

И даже это работает:

>>> Foo.bar(z, y=3, x=1)
1 3

Но почему это не работает?

>>> Foo.bar(self=z, y=3, x=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)

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

1 Ответ

6 голосов
/ 14 марта 2010

z.bar - это метод bound - он уже имеет атрибут im_self, который становится первым аргументом (условно названным self) для базового объекта функции, im_func привязанного метода приписывать. Чтобы переопределить это, вам, очевидно, нужно повторно связать im_self ( edit : или вместо этого вызвать im_func) - что бы вы ни делали с точки зрения передачи аргументов, это никак не повлияет на это, конечно. Да, это документированный способ привязанных методов , работающий в Python (не просто деталь реализации: каждая правильная реализация Python должна делать это именно так). Таким образом, это «необходимо» в том смысле, что оно является частью того, что делает Python именно тем языком, которым он является, в отличие от того, чтобы быть немного или сильно отличным языком. Конечно, вы можете разработать другой язык, который будет играть по совершенно другим правилам, но - конечно, это не будет Python.

Редактировать : правки ОП разъяснили, что он вызывает несвязанный метод, а не связанный метод. Это все еще не работает, и причина ясна из сообщения об ошибке, которое пытается получить:

TypeError: метод unbound bar () должен вызываться с экземпляром Foo первым аргумент (вместо этого ничего не получил)

Правило, лежащее в основе этого очень четкого сообщения об ошибке, состоит в том, что экземпляр должен быть первым аргументом (поэтому, конечно, позиционный: именованные аргументы не имеют порядка). Несвязанный метод не «знает» (и не заботится), каким может быть имя этого параметра (и использование имени self для него - всего лишь соглашение , не правило языка Python): его заботит только однозначное условие «первого аргумента» (среди позиционных, конечно).

Этот непонятный угловой случай, безусловно, может быть изменен (с помощью патча Python 3.2, если и когда изменение языка закончится, «заморозить» ;-), сделав несвязанные методы серьезно более сложными: им придется проанализировать и сохранить первый -argument name во время создания и проверять аргументы ключевых слов при каждом вызове на случай, если кто-то передаст self по имени, а не по позиции. Я не думаю, что это сломало бы любой существующий, работающий код, это только замедлило бы почти каждую существующую программу Python. Если вы напишите и предложите патч, реализующий эту сложность, и станете активными на python-dev, чтобы защищать его от неизбежной огненной бури противодействия, у вас, без сомнения, будет шанс> 0 пробить его - удачи .

Тем временем остальные из нас будут продолжать получать атрибут im_func, как один абсурдно крошечный дополнительный шаг в том, что должно быть довольно сложным встроенным зданием метапрограммирования, чтобы оправдать такое изменение - это не так. вообще «особый случай», по сравнению с ужасными трудностями адаптации передачи именованных аргументов к встроенным , которые не принимают именованных аргументов (и не раскрывают их) имен аргументов «легко разрешить преобразование именованных аргументов в позиционные (теперь , на которые будет стоить атаковать ветряная мельница, ИМХО: из всех вызываемых, встроенные являются наихудшими для метапрограммы, из-за этого! 1046 *

...