2011-10-12 8 views
6

Uno de mis unittests comprueba si un rango está configurado correctamente después de leer un archivo de registro, y me gustaría simplemente probar var == range(0,10). Sin embargo, range(0,1) == range(0,1) evalúa a False en Python 3.Cómo probar la equivalencia de rangos

¿Existe alguna manera directa de probar la equivalencia de rangos en Python 3?

+2

¿Por qué estás comparando dos rangos? –

+0

Mi unittest solo afirma que el rango fue construido correctamente. En el programa, en lugar de almacenar los valores mínimos y máximos aceptables, almaceno el rango y luego pruebo si val en el rango. – oneporter

Respuesta

10

En python3 range, devuelve un iterable de tipo range. Dos range s son iguales si y sólo si son idénticos (es decir, comparten la misma id.) Para probar la igualdad de sus contenidos, convertir el range a un list:

list(range(0,1)) == list(range(0,1)) 

Esto funciona muy bien para distancias cortas. Para rangos muy largos, Charles G Waldman's solution es mejor.

+0

@oneporter: Tenga en cuenta que esto consume el iterador y no podrá volver a consultarlo más tarde. –

+2

@StevenRumbalski: Como los objetos 'range' son iterables y no iteradores, no pueden ser" consumidos ". [Puede iterar sobre ellos varias veces.] (Http://ideone.com/RGvxv) –

+2

@Sven Marnach. Excelente. Gracias por la corrección. –

1

Trate assertItemsEqual, (en el docs):

class MyTestCase(unittest.TestCase): 
    def test_mytest(self): 
     a = (0,1,2,3,4) 
     self.assertItemsEqual(a, range(0,4)) 
+0

Tenga en cuenta que assertItemsEqual no está disponible en py3, que es lo que el OP está pidiendo. – jmagnusson

6

La primera solución propuesta - use "list" para convertir los rangos en listas - es ineficaz, ya que primero convertirá los objetos del rango en listas (potencialmente consumiendo mucha memoria, si los rangos son grandes), luego comparará cada elemento. Considere, por ejemplo, a = rango (1000000), el objeto "rango" en sí mismo es pequeño pero si lo coacciona a una lista se vuelve enorme. Entonces tienes que comparar un millón de elementos.

La respuesta (2) es aún menos eficiente, ya que assertItemsEqual no solo va a crear instancias de las listas, sino que las va a ordenar también antes de hacer la comparación de elementos.

En su lugar, ya que sabe que los objetos son rangos, son iguales cuando sus zancadas, los valores de inicio y final son iguales. P.ej.

ranges_equal = len(a)==len(b) and (len(a)==0 or a[0]==b[0] and a[-1]==b[-1])

+3

Esto no funcionará si los rangos son paso. Por ejemplo, el rango (1,20,2) y el rango (1,20) serían equivalentes. – krs1

+0

Buen punto krs1. Creo que mi enfoque podría solucionarse comparando también el len() de los rangos ...ranges_equal = (len (a) == len (b) y a [0] == b [0] y a [-1] == b [-1]) –

+0

O, si evita problemas con rangos vacíos: 'ranges_equal = len (a) == len (b) == 0 o len (a) == len (b) y a [0] == b [0] y a [-1] == b [-1] ' –

1

Otra manera de hacerlo:

ranges_equal = str(a)==str(b)

La representación de cadena indica el comienzo, el final y el paso de los rangos.

Esta pregunta me hace pensar que tal vez Python debería proporcionar una forma de obtener estos atributos del propio objeto de rango.

Cuestiones relacionadas