Rendimiento de len (Lista) vs lectura de una variable

Una pregunta similar ya ha sido la función de Costo de len () aquí. Sin embargo, esta pregunta analiza el costo de la autoaprendizaje. Supongamos que tengo un código que se repite muchas veces len(List) , cada vez que es O(1) , la lectura de una variable también es O(1) más la asignación es O(1) .

Como nota al margen, me parece que n_files = len(Files) es algo más legible que el len(Files) repetido len(Files) en mi código. Entonces, eso ya es un incentivo para que yo haga esto. También podría argumentar en mi contra, que en algún lugar del código se pueden modificar los Files , por lo que n_files ya no es correcto, pero ese no es el caso.

Mi pregunta es:
¿Hay una cantidad de llamadas a len(Files) después de las cuales acceder a n_files será más rápido?

Algunos resultados (tiempo, en segundos, para un millón de llamadas), con una lista de diez elementos usando Python 2.7.10 en Windows 7; store es si almacenamos la longitud o seguimos llamando a len , y alias es si creamos o no un alias local para len :

 Store Alias n= 1 10 100 Yes Yes 0.862 1.379 6.669 Yes No 0.792 1.337 6.543 No Yes 0.914 1.924 11.616 No No 0.879 1.987 12.617 

y una lista de mil elementos:

 Store Alias n= 1 10 100 Yes Yes 0.877 1.369 6.661 Yes No 0.785 1.299 6.808 No Yes 0.926 1.886 11.720 No No 0.891 1.948 12.843 

Conclusiones:

  • Almacenar el resultado es más eficiente que llamar a len repetidamente, incluso para n == 1 ;
  • Crear un alias local para len puede hacer una pequeña mejora para n más grandes donde no estamos almacenando el resultado, pero no tanto como lo haría el almacenamiento del resultado; y
  • La influencia de la longitud de la lista es insignificante, lo que sugiere que si los enteros están internados o no no está haciendo ninguna diferencia.

Guión de prueba:

 def test(n, l, store, alias): if alias: len_ = len len_l = len_(l) else: len_l = len(l) for _ in range(n): if store: _ = len_l elif alias: _ = len_(l) else: _ = len(l) if __name__ == '__main__': from itertools import product from timeit import timeit setup = 'from __main__ import test, l' for n, l, store, alias in product( (1, 10, 100), ([None]*10,), (True, False), (True, False), ): test_case = 'test({!r}, l, {!r}, {!r})'.format(n, store, alias) print test_case, len(l), print timeit(test_case, setup=setup) 

Las llamadas a funciones en Python son costosas, por lo que si está 100% seguro de que el tamaño de n_files no cambiará cuando acceda a su longitud desde la variable, puede usar la variable, si eso es lo que también es más legible para usted.

Una prueba de rendimiento de ejemplo para acceder a len(list) y acceder desde la variable, da el siguiente resultado:

 In [36]: l = list(range(100000)) In [37]: n_l = len(l) In [40]: %timeit newn = len(l) 10000000 loops, best of 3: 92.8 ns per loop In [41]: %timeit new_n = n_l 10000000 loops, best of 3: 33.1 ns per loop 

Acceder a la variable siempre es más rápido que usar len() .

Usar l = len(li) es más rápido:

 python -m timeit -s "li = [1, 2, 3]" "len(li)" 1000000 loops, best of 3: 0.239 usec per loop python -m timeit -s "li = [1, 2, 3]; l = len(li)" "l" 10000000 loops, best of 3: 0.0949 usec per loop 

Es probable que el uso de len(Files) lugar de n_files sea ​​más lento. Sí, tiene que buscar n_files , pero en el primer caso tendrá que buscar tanto len como Files y luego, encima de esa llamada, una función que “calcula” la longitud de los Files .