2010-10-27 13 views
5

Tengo el siguiente código que estoy tratando de entender:entendimiento __call__ y list.sort (clave)

>>> class DistanceFrom(object): 
     def __init__(self, origin): 
      self.origin = origin 
     def __call__(self, x): 
      return abs(x - self.origin) 

>>> nums = [1, 37, 42, 101, 13, 9, -20] 
>>> nums.sort(key=DistanceFrom(10)) 
>>> nums 
[9, 13, 1, 37, -20, 42, 101] 

¿Puede alguien explicar cómo funciona esto? Por lo que he entendido, __call__ es lo que se llama cuando se llama object(), llamando al objeto como una función.

Lo que no entiendo es cómo nums.sort(key=DistanceFrom(10)). ¿Como funciona esto? ¿Alguien puede explicar esta línea?

Gracias!

Respuesta

7

Aquí he definido una función DistanceFrom() que se puede utilizar de una manera similar a la clase, pero podría ser más fácil de seguir

>>> def DistanceFrom(origin): 
...  def f(x): 
...   retval = abs(x - origin) 
...   print "f(%s) = %s"%(x, retval) 
...   return retval 
...  return f 
... 
>>> nums = [1, 37, 42, 101, 13, 9, -20] 
>>> nums.sort(key=DistanceFrom(10)) 
f(1) = 9 
f(37) = 27 
f(42) = 32 
f(101) = 91 
f(13) = 3 
f(9) = 1 
f(-20) = 30 
>>> nums 
[9, 13, 1, 37, -20, 42, 101] 

Así se ve que el objeto devuelto por DistanceFrom es llama una vez para cada elemento de numsnums y luego se devuelve una selección de conformidad con los valores devueltos

+0

¡Gracias! Esto es perfecto. – user225312

+0

@Alfred, eres bienvenido –

4

Ordena la lista nums en su lugar utilizando un objeto de función keyDistanceFrom(10). Debe ser invocable porque key debe ser invocable. La salida resultante se ordena por su "distancia" de 10, es decir 9 es el valor más cercano a 10, 101 es el más lejano.

Después de que el objeto se inicializa y pasa como un parámetro key con el método sort, en cada iteración será llamado con el valor actual (que es lo x es) y valor devuelto se utilizarían para determinar la posición x 's en la lista resultante.

+0

¿Cómo se ejecuta? Quiero decir, DistanceFrom (10) establece self.origin = 10. ¿Después de eso? – user225312

+0

@Alfred: ver mi edición – SilentGhost

+0

"__ init __" es un constructor al que se llama durante la creación de la clave Object – OlimilOops

8

__call__ en python permite que una clase se ejecute como si fuera una función. Puede probar esto de forma manual:

>>> dis = DistanceFrom(10) 
>>> print dis(10), dis(5), dis(0) 
0 5 10 
>>> 

¿Qué clase hace es llamar a esa función para cada artículo en su lista y utiliza el valor devuelto como clave de ordenación. En este ejemplo, obtendrá una lista con los artículos más cercanos al 10 primero y uno más hacia el final.

+0

Aah. Esto es bueno. – user225312

+0

@user: Su respuesta fue perfecta, pero acepté la respuesta de gnibbler, ya que sería beneficioso para los principiantes en caso de que lo busquen. – user225312

1

Cuando llama a algo que significa que espera que devuelva un valor. Cuando crea una clase que tiene el método __call__ definido, está dictando que una instancia de esa clase puede comportarse como una función.

Para el propósito de esta pregunta, esto:

class DistanceFrom(object): 
     def __init__(self, origin): 
      self.origin = origin 
     def __call__(self, x): 
      return abs(x - self.origin) 

es funcionalmente equivalente a:

def distance_from(origin, other): 
    return abs(other - origin) 

En cuanto al argumento key para ordenar, aquí está su explicación directamente de la documentación de Python:

clave especifica una función de un argumento que se utiliza para extraer una clave de comparación de cada elemento de la lista: key=str.lower.El valor por defecto es Ninguno (compárese con los elementos directamente)

1

Los documentos de Python son bastante buenos cada vez que encuentro que no entiendo los fundamentos. Localicé estos con google.

The key parameter es una función que sort llamará a los elementos de la lista. Localicé este documento buscando en Google sort site:http://docs.python.org/ y luego buscando key=.

__call__ es una función que puede agregar a un objeto para hacer que ese objeto se llame como si fuera una función. Encontré este documento buscando en Google __call__ site:http://docs.python.org/ y luego siguiendo el enlace al documento para __call__.

+0

Entiendo cuáles son, mi pregunta fue específica para este ejemplo. – user225312