numpy.r_ no es una función. ¿Qué es?

De acuerdo con el documento numpy / scipy en numpy.r_ aquí , “no es una función, por lo que no toma parámetros”.

Si no es una función, ¿cuál es el término adecuado para “funciones” como numpy.r_ ?

Es una instancia de clase (también conocido como un objeto):

 In [2]: numpy.r_ Out[2]:  

Una clase es una construcción que se utiliza para definir un tipo distinto, ya que dicha clase permite instancias de sí misma. Cada instancia puede tener propiedades (miembro / variables de instancia y métodos).

Uno de los métodos que puede tener una clase es el método __getitem__ , que se llama siempre que agregue [something,something...something] al nombre de la instancia. En el caso de la instancia numpy.r_ , el método devuelve una matriz numpy.

Tome la siguiente clase, por ejemplo:

 class myClass(object) def __getitem__(self,i) return i*2 

Mira estas salidas para la clase anterior:

 In [1]: a = myClass() In [2]: a[3] Out[2]: 6 In [3]: a[3,4] Out[3]: (3, 4, 3, 4) 

Estoy llamando al método __getitem__ de myClass (a través de los paréntesis [] ) y el método __getitem__ está devolviendo (el contenido de una lista * 2 en este caso) – no es la clase / instancia que se comporta como una función, es el __getitem__ Función de la instancia myClass que se está llamando.

En una nota final, notará que para crear myClass instancia de myClass tuve que hacer a = myClass() mientras que para obtener una instancia de RClass usamos numpy.r_ Esto se debe a que numpy crea una instancia de RClass y lo vincula al nombre numpy.r_. Esta es la línea relevante en el código fuente numpy . En mi opinión, esto es bastante feo y confuso!

Yo diría que para todos los propósitos r_ es una función, pero una implementada por un hack inteligente que usa una syntax diferente. Mike ya explicó cómo r_ en realidad no es una función, sino una instancia de clase de RClass , que tiene implementado __getitem__ , de modo que puede usarlo como r_[1] . La diferencia estética es que utiliza corchetes en lugar de curvos, por lo que no está haciendo una llamada de función, pero en realidad está indexando el objeto. Aunque esto es técnicamente cierto, para todos los propósitos, funciona igual que una llamada de función, pero que permite cierta syntax adicional no permitida por una función normal.

La motivación para crear r_ probablemente proviene de la syntax de Matlab, que permite construir matrices de una manera muy compacta, como x = [1:10, 15, 20:10:100] . Para lograr lo mismo en números, tendrías que hacer x = np.hstack((np.arange(1,11), 15, np.arange(20,110,10))) . El uso de dos puntos para crear rangos no está permitido en python, pero existen en forma de notación de división para indexar en una lista, como L[3:5] , e incluso A[2:10, 20:30] para múltiples matrices tridimensionales. Bajo el capó, esta notación de índice se transforma en una llamada al método __getitem__ del objeto, donde la notación de dos puntos se transforma en un objeto de división:

 In [13]: class C(object): ...: def __getitem__(self, x): ...: print x In [14]: c = C() In [15]: c[1:11, 15, 20:110:10] (slice(1, 11, None), 15, slice(20, 110, 10)) 

El objeto r_ ‘abusa’ de este hecho para crear una ‘función’ que acepta la notación de división, que también hace algunas cosas adicionales, como concatenar todo y devolver el resultado, para que pueda escribir x = np.r_[1:11, 15, 20:110:10] . El “No es una función, así que no toma parámetros” en la documentación es ligeramente engañoso …