2010-01-24 15 views
5

Entonces, cPython (2.4) tiene un comportamiento interesante cuando la longitud de algo se acerca a 1 < < 32 (el tamaño de un int).Python, len y tamaño de ints

r = xrange(1<<30) 
assert len(r) == 1<<30 

está bien, pero:

r = xrange(1<<32) 
assert len(r) == 1<<32 
ValueError: xrange object size cannot be reported`__len__() should return 0 <= outcome 

de Alex wowrange tiene este comportamiento también. wowrange(1<<32).l está bien, pero len(wowrange(1<<32)) es malo. Supongo que hay algo de comportamiento de punto flotante (que se lee como negativo) que está ocurriendo aquí.

  1. ¿Qué está pasando exactamente aquí? (¡Esto está bastante bien resuelto a continuación!)
  2. ¿Cómo puedo evitarlo? Longs?

(Mi aplicación específica es random.sample(xrange(1<<32),ABUNCH)) si la gente quiere hacer frente a esa pregunta directamente!)

+0

@Gregg, lo suficientemente gracioso obtengo OverflowError en lugar de ValueError (como lo hace la A aceptada a esa Q), pero, de minimis. El problema es que, para su aplicación específica, desea un 'random.sample' que no cabe en la memoria, pero cada estructura de Python ** debe ** encajar en la memoria. Si abre otra Q y especifica los parámetros con más detalle quizás sea más práctico ofrecer ayuda con la aplicación específica ... –

+0

@Alex, en realidad, la muestra no tiene que caber en la memoria, sino en 2.4 (lo sé, ¡noticias viejas!) módulo aleatorio, ¡hace una llamada len() que falla! xrange (1 << 32) en sí mismo está bien, pero la llamada: n = len (población) en 299 del módulo no lo está. –

+0

'random.sample' necesita' llamar a len() 'en Python 2.5, 2.6, 3.0 y 3.1 también, y esa llamada falla en' xrange (1 << 32) 'en cada versión (desde' len() 'solo se aplica a contenedores que" caben en la memoria "y que' xrange' conceptualmente no). Entonces, si especifica mejor qué es exactamente lo que necesita, esp. ¿Cuál es el valor típico de 'ABUNCH', podemos sugerir cómo evitar esta limitación de 'random.sample' (que se aplica a _todas las versiones de Python alrededor de! -). Mejor hecho en una Q diferente, en mi humilde opinión. –

Respuesta

11

cPython supone que las listas caben en la memoria. Esto se extiende a objetos que se comportan como listas, como xrange. esencialmente, la función len espera que el método __len__ devuelva algo que se puede convertir a size_t, lo que no sucederá si la cantidad de elementos lógicos es demasiado grande, incluso si esos elementos no existen realmente en la memoria.

+0

gracias por explicar por qué 'len' en particular se está comportando de esta manera. cPython len espera 'size_t'. –

+0

Objeción menor: el hecho de que una longitud sea demasiado grande para un 'size_t' no significa que el objeto no cabe en la memoria. Por ejemplo, tengo una clase que representa un campo de bit para el cual '__len__' deja de funcionar para objetos de más de 256 MB en Python de 32 bits. –

1

1<<32, cuando se trata como un entero, es negativo.

5

Encontrará que

xrange(1 << 31 - 1) 

es el último que se comporta como desee. Esto se debe a la máxima firmado (32 bits) es número entero 2^31 - 1.

1 << 32 no es un positivo entero de 32 bits (int tipo de datos de Python), así que por eso que está recibiendo ese error.

En Python 2.6, ni siquiera puedo hacer xrange(1 << 32) o xrange(1 << 31) sin obtener un error, y mucho menos len en el resultado.

Editar Si quieres un poco más de detalle ...

1 << 31 representa el número 0x80000000, que en representación de complemento a 2 es el número negativo representable más bajo (-1 * 2^31) de 32 bits int. Así que sí, debido a la representación de los números con los que estás trabajando en bits, en realidad se está volviendo negativo.

Para un número de complemento de 2 de 32 bits, 0x7FFFFFFF es el número entero más alto que se puede representar (2^31 - 1) antes de "desbordamiento" en números negativos.

Further reading, si te interesa.

Tenga en cuenta que cuando ve algo como 2147483648L en el aviso, la "L" al final significa que ahora se representa como un "entero largo" (64 bits, por lo general, no puedo hacer ninguna promesa sobre cómo Python lo maneja porque no lo he leído).

+1

Prueba 'hex (1 << 32)' y mira lo que obtienes. Sugerencia: no es 0x80000000. –

+0

Typo, perdón, corregido. – Sapph

Cuestiones relacionadas