2012-01-18 6 views
8

El operator.itemgetter() función funciona así:Python: funciones devueltos por itemgetter() no funciona como se espera en las clases

>>> import operator 
>>> getseconditem = operator.itemgetter(1) 
>>> ls = ['a', 'b', 'c', 'd'] 
>>> getseconditem(ls) 
'b' 

Editar He añadido esta parte para resaltar la inconsitency

>>> def myitemgetter(item): 
...  def g(obj): 
...   return obj[item] 
...  return g 
>>> mygetseconditem = myitemgetter(1) 

Ahora, tengo esta clase

>>> class Items(object): 
...  second = getseconditem 
...  mysecond = mygetseconditem 
... 
...  def __init__(self, *items): 
...   self.items = items 
... 
...  def __getitem__(self, i): 
...   return self.items[i] 

Acceso al segundo elemento con su índice funciona

>>> obj = Items('a', 'b', 'c', 'd') 
>>> obj[1] 
>>> 'b' 

y lo mismo ocurre para acceder a él a través de la mysecond método

>>> obj.mysecond() 
'b' 

Pero por alguna razón, utilizando el método second() genera una excepción

>>> obj.second() 
TypeError: itemgetter expected 1 arguments, got 0 

¿Qué ofrece?

Respuesta

7

obj.second es la función getseconditem. Una función que espera que un argumento funcione. Como llama al obj.second sin ningún argumento, se genera el error que dio. Para resolverlo se puede hacer obj.second(obj.items)second o definir de otro modo:

class Items(object): 
    def __init__(self, *items): 
     self.items = items 

    def __getitem__(self, i): 
     return self.items[i] 

    def second(self): 
     return getseconditem(self.items) 

Editar

Está claro lo que quiere decir ahora, después de que ha editado su pregunta. Creo que lo que está sucediendo aquí es que debido a que getseconditem no es una función definida por el usuario, no se transforma en un método al acceder al obj.second. Simplemente se mantiene como una función. El siguiente se puede encontrar en el docs:

Nota que la transformación de objeto de función a (no unido o unido ) método objeto ocurre cada vez que el atributo se recupera de la clase o instancia. En algunos casos, una optimización fructífera es asignar el atributo a una variable local y llamar a esa variable local. Observe también que esta transformación solo ocurre para las funciones definidas por el usuario; otros objetos invocables (y todos los objetos no llamables) son recuperados sin transformación.

+0

Técnicamente, dado que se llama como método, generalmente se obtiene a sí mismo como una opción automática. Mi suposición es que asociar la función al objeto de esa manera hace que el tiempo de ejecución lo trate como un método "estático". Puede haber un decorador que pueda usar para forzarlo a tratarlo como un método. – Cyclone

+0

@Rob Wouters: Creo que mi pregunta es qué hace que mi tarea 'mysecond = mygetseconditem' sea especial. ¿Por qué funciona uno y el otro no? –

+0

@mike, he editado mi respuesta para agregar lo que creo que está causando la discrepancia. –

1

el problema parece ser el siguiente:

>>> print (getseconditem, mygetseconditem) 
(<operator.itemgetter object at 0x01EE5BD0>, <function g at 0x00504DB0>) 

En otras palabras, una función puede ser atado, sino un exigible no puede.

+0

Esto no funcionará porque 'getseconditem' pasará la' clase' y no la instancia y, por lo tanto, no puede acceder a 'self.items' (o' self .__ getitem__'). –

+0

@ rob-wouters, buen punto! Pero el problema parece ser más profundo. – newtover

Cuestiones relacionadas