2012-09-13 22 views
8

Al tratar de abordar un problema más complejo, comencé a comparar la velocidad de acceso con las variables locales frente a las variables miembro.¿Por qué el acceso variable local es más rápido que el acceso de miembro de clase en Python?

Aquí un programa de prueba:

#!/usr/bin/env python 

MAX=40000000 

class StressTestMember(object): 
    def __init__(self): 
     self.m = 0 

    def do_work(self): 
     self.m += 1 
     self.m *= 2 

class StressTestLocal(object): 
    def __init__(self): 
     pass 

    def do_work(self): 
     m = 0 
     m += 1 
     m *= 2 

# LOCAL access test 
for i in range(MAX): 
    StressTestLocal().do_work() 

# MEMBER access test 
for i in range(MAX): 
    StressTestMember().do_work() 

Sé que puede parecer una mala idea para crear una instancia StressTestMember y StressTestLocal en cada uno de iteraciones pero tiene sentido en el programa de modelado, donde estos son básicamente Active Records.

Después de un simple punto de referencia,

  • LOCAL prueba de acceso: 0m22.836 prueba de acceso MIEMBRO
  • : 0m32.648s

La versión local es de ~ 33% más rápido, mientras que sigue siendo parte de una clase. ¿Por qué?

Respuesta

19

self.m += 1 significa que tiene que mirar hacia arriba una variable local llamada self y luego encontrar el atributo llamado m

Por supuesto, si sólo hay que mirar hacia arriba una variable local, que será más rápido sin el paso adicional.

Puede ser útil para ver lo que está sucediendo bajo el capó:

>>> import dis 
>>> dis.dis(StressTestLocal.do_work) 
18   0 LOAD_CONST    1 (0) 
       3 STORE_FAST    1 (m) 

19   6 LOAD_FAST    1 (m) 
       9 LOAD_CONST    2 (1) 
      12 INPLACE_ADD   
      13 STORE_FAST    1 (m) 

20   16 LOAD_FAST    1 (m) 
      19 LOAD_CONST    3 (2) 
      22 INPLACE_MULTIPLY  
      23 STORE_FAST    1 (m) 
      26 LOAD_CONST    0 (None) 
      29 RETURN_VALUE   
>>> dis.dis(StressTestMember.do_work) 
10   0 LOAD_FAST    0 (self) 
       3 DUP_TOP    
       4 LOAD_ATTR    0 (m) 
       7 LOAD_CONST    1 (1) 
      10 INPLACE_ADD   
      11 ROT_TWO    
      12 STORE_ATTR    0 (m) 

11   15 LOAD_FAST    0 (self) 
      18 DUP_TOP    
      19 LOAD_ATTR    0 (m) 
      22 LOAD_CONST    2 (2) 
      25 INPLACE_MULTIPLY  
      26 ROT_TWO    
      27 STORE_ATTR    0 (m) 
      30 LOAD_CONST    0 (None) 
      33 RETURN_VALUE   
+2

+1 Muy bien, una respuesta clara. – Tadeck

+0

muy agradable. esto merece la aceptación. –

+0

Entonces, ¿sería sabio crear una nueva referencia a una variable de clase en el ámbito local? por ejemplo, 'm = self.m'? No haría ninguna diferencia en esta prueba, pero mi versión de 'do_work()' es un ciclo que se ejecuta millones de veces. –

5

Los nombres locales son más rápidos porque Python realiza una optimización de que los nombres locales no necesitan acceso a Dict, por otro lado, los atributos de instancia necesitan acceder al __dict__ del objeto.

Esta es también la razón por la que los nombres locales son más rápidos que los nombres globales.

Cuestiones relacionadas