2010-08-28 15 views
20

Me pregunto si hay una biblioteca desde la que usaré al menos 2 métodos, ¿hay alguna diferencia en el rendimiento o el uso del ram entre: de X import method1, method2 y esto import X Sé sobre espacios de nombres y cosas así, pero me pregunto si Python es lo suficientemente inteligente como para saber que usaré solo 2 métodos.Python import X o de X import Y? (rendimiento)

Respuesta

8

No hay memoria ni diferencia de velocidad (todo el módulo debe evaluarse de cualquier manera, porque la última línea podría ser Y = something_else). A menos que su computadora sea de la década de 1980, no importa de todos modos.

+0

En mi proyecto, hacer 40 importaciones desde PyQt5 causa un retraso de 500 ms durante el inicio, lo que me parece inaceptable. Eso está en SSD e i7-4790K. Debido a esto, probablemente cambie a C++, así que sí, es importante ... quizás no en el contexto de la pregunta de OP, pero muestra que las importaciones pueden causar problemas de rendimiento. –

4

No creo que haya ninguna diferencia real, y en general preocuparse por esa pequeña cantidad de memoria no suele valer la pena. Si va a presionar las consideraciones de memoria, lo más probable es que esté en su código.

28

Existe una diferencia, porque en la versión import x hay dos búsquedas de nombres: una para el nombre del módulo y la segunda para el nombre de la función; por otro lado, usando from x import y, solo tiene una búsqueda.

Esto se puede ver muy bien, utilizando el módulo DIS:

import random 
def f_1(): 
    random.seed() 

dis.dis(f_1) 
    0 LOAD_GLOBAL    0 (random) 
    3 LOAD_ATTR    0 (seed) 
    6 CALL_FUNCTION   0 
    9 POP_TOP 
    10 LOAD_CONST    0 (None) 
    13 RETURN_VALUE 

from random import seed 

def f_2(): 
    seed() 

dis.dis(f_2) 
    0 LOAD_GLOBAL    0 (seed) 
    3 CALL_FUNCTION   0 
    6 POP_TOP 
    7 LOAD_CONST    0 (None) 
    10 RETURN_VALUE 

Como se puede ver, el uso de la forma from x import y es un poco más rápido. Por ejemplo, import x es menos costoso que from x import y, porque hay una búsqueda de nombre menos; vamos a ver el código desensamblado:

def f_3(): 
    import random 

dis.dis(f_3) 
    0 LOAD_CONST    1 (-1) 
    3 LOAD_CONST    0 (None) 
    6 IMPORT_NAME    0 (random) 
    9 STORE_FAST    0 (random) 
    12 LOAD_CONST    0 (None) 
    15 RETURN_VALUE 

def f_4(): 
    from random import seed 

dis.dis(f_4) 
    0 LOAD_CONST    1 (-1) 
    3 LOAD_CONST    2 (('seed',)) 
    6 IMPORT_NAME    0 (random) 
    9 IMPORT_FROM    1 (seed) 
    12 STORE_FAST    0 (seed) 
    15 POP_TOP 
    16 LOAD_CONST    0 (None) 
    19 RETURN_VALUE 

no sé la razón, pero parece que la forma from x import y se parece a una llamada a la función, y por lo tanto es aún más caro de lo previsto; por esta razón, si la función importada se usa solo una vez, significa que sería más rápido usar import x, mientras que si se usa más de una vez, entonces es más rápido usar from x import y.

Dicho esto, como de costumbre, le sugiero no siguiendo este conocimiento para su decisión sobre cómo importar módulos y funciones, porque esto es solo una optimización prematura.
Personalmente, creo que en muchos casos, los espacios de nombres explícitos son mucho más legibles, y le sugiero que haga lo mismo: use su propio sentido estético :-)

+0

@sdolan: Sus resultados de tiempo parecen sugerir que 'import x' es más rápido que 'from x import y', que parece funcionar de forma contraria a lo que podría esperar después de ver' dis.dis'. Bastante curioso. – unutbu

+0

@ ~ unutbu. Creo que la diferencia es que para 'from x import y', python debe hacer un trabajo extra para ubicar' y' en 'x'. Cuando esto se repite una vez por cada llamada a 'y', como estaba en la prueba de sdolans, probablemente se vuelve más costoso que una simple declaración de' importación'. – aaronasterling

+1

** Actualización: ** Aquí hay algunos resultados de tiempo que prueban el ** contrario ** que 'de x import y' es más rápido (p tiene un alias a python2.6): p -m timeit" import random; random.seed () "10000 bucles, mejor de 3: 27.7 usec por bucle p -m timeit" de semilla de importación aleatoria; seed() "10000 bucles, mejor de 3: 29.2 usec por bucle Las mismas pruebas en 3.1 tuvieron los mismos resultados. – sdolan

3

Puede importar si está llamando a una función muchas veces en un bucle (millones o más). Hacer la búsqueda del diccionario doble eventualmente se acumulará. El siguiente ejemplo muestra un aumento del 20%.

Los tiempos indicados son para Python 3.4 en una máquina Win7 de 64 bits. (Cambie el comando de rango a xrange para Python 2.7).

Este ejemplo está muy basado en el libro , aunque su tercer ejemplo de búsqueda de funciones locales es mejor ya no parecía contener para mí.

import math 
from math import sin 

def tight_loop_slow(iterations): 
    """ 
    >>> %timeit tight_loop_slow(10000000) 
    1 loops, best of 3: 3.2 s per loop 
    """ 
    result = 0 
    for i in range(iterations): 
     # this call to sin requires two dictionary lookups 
     result += math.sin(i) 

def tight_loop_fast(iterations): 
    """ 
    >>> %timeit tight_loop_fast(10000000) 
    1 loops, best of 3: 2.56 s per loop 
    """ 
    result = 0 
    for i in range(iterations): 
     # this call to sin only requires only one lookup 
     result += sin(i)