¿Por qué no puedo pasar yo mismo como un argumento con nombre a un método de instancia en Python?

Esto funciona:

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

Y esto funciona:

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

E incluso esto funciona:

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

Pero ¿por qué no funciona esto?

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

Esto hace que la metaprogtwigción sea más difícil, ya que requiere un manejo especial de casos. Tengo curiosidad si es de alguna manera necesario por la semántica de Python o simplemente un artefacto de implementación.

z.bar es un método enlazado : ya tiene un atributo im_self que se convierte en el primer argumento (convencionalmente denominado self ) para el objeto de función subyacente, el atributo im_func del método im_func . Para anular que obviamente necesitas volver a enlazar im_self ( edita : o llama a im_func en im_func lugar), por im_func , lo que hagas en términos de transmisión de argumentos no tendrá ningún efecto en ello. Sí, esa es la forma documentada en que trabajan los objetos enlazados en Python (no solo un detalle de implementación: cada implementación correcta de Python tiene que hacerlo exactamente de esta manera). Así que es “necesario” en el sentido de que es parte de lo que hace a Python exactamente el idioma que es, en lugar de ser un lenguaje ligeramente diferente o muy diferente. Por supuesto, puedes diseñar un lenguaje diferente que elija jugar con reglas completamente diferentes, pero, por supuesto, no sería Python.

Edición : las ediciones del OP aclararon que está llamando a un método independiente , no a uno vinculado. Esto todavía no funciona, y la razón es clara a partir del mensaje de error que obtiene el bash:

TypeError: la barra de método no enlazada () debe llamarse con la instancia de Foo como primer argumento (no obtuvo nada en su lugar)

La regla que subyace a este mensaje de error muy claro es que la instancia debe ser el primer argumento (por lo tanto, uno posicional: los argumentos con nombre no tienen ordenamiento). El método no consolidado no “sabe” (ni le importa) cuál sea el nombre de ese parámetro (y el uso del nombre self para él es solo una convención , no una regla del lenguaje Python): solo se preocupa por la condición inequívoca de “Primer argumento” (entre los posicionales, por supuesto).

Este caso de la esquina oscura sin duda podría modificarse (con un parche de Python 3.2, si el cambio de lenguaje se “congela” cuando se produce un cambio en el lenguaje 😉 haciendo que los métodos no vinculados sean mucho más complicados: tendrían que realizar una introspección y guardar el nombre del primer argumento. en el momento de la creación, y verifique los argumentos de las palabras clave en cada llamada, en caso de que alguien pase por su nombre en lugar de por posición. No creo que esto rompa ningún código existente que funcione, solo ralentizaría casi todos los progtwigs Python existentes. Si escribe y propone un parche para implementar esta complicación, y se activa en python-dev para abogar contra la tormenta de fuego que está por venir, no hay duda de que tiene una oportunidad> 0 de lograrlo – buena suerte .

Mientras tanto, el rest de nosotros seguiremos obteniendo el atributo im_func , como un paso extra absurdamente diminuto en lo que tiene que ser un edificio de metaprogtwigción bastante complicado para justificar tal cambio, no es un “caso especial” en absoluto, en comparación con las terribles dificultades de adaptar el paso de argumentos con nombre a elementos incorporados que no toman argumentos con nombre (y no exponen sus “nombres de argumento” para permitir fácilmente la transformación de argumentos con nombre en posicionales (ahora eso sería un molino de viento que vale la pena atacar, en mi humilde opinión: ¡de todos los callables, las construcciones son las peores metaprogtwigs, debido a eso! -).