2012-09-13 11 views
8

Mentre cercavo di affrontare un problema più complesso, sono arrivato a confrontare la velocità di accesso con variabili locali vs variabili membro.Perché l'accesso alle variabili locali è più veloce dell'accesso ai membri della classe in Python?

Ecco un programma di test:

#!/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() 

So che potrebbe sembrare una cattiva idea per istanziare StressTestMember e StressTestLocal su ogni iterazioni, ma ha senso nel programma modellato in cui questi sono fondamentalmente record attivi.

Dopo un semplice punto di riferimento,

  • LOCALE test di accesso: 0m22.836
  • test di accesso MEMBRO: 0m32.648s

La versione locale è ~ 33% più veloce mentre ancora parte della una classe. Perché?

risposta

19

self.m += 1 significa che dovete osservare in su una variabile locale chiamata self e poi trovare l'attributo chiamato m

Naturalmente se avete solo per cercare una variabile locale, sarà più veloce senza il passaggio intermedio.

Può essere utile a guardare a ciò che sta accadendo sotto il cofano:

>>> 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 Molto buono, risposta chiara. – Tadeck

+0

molto bello. questo merita l'accettazione. –

+0

Quindi, sarebbe saggio creare un nuovo riferimento a una variabile di classe in ambito locale? ad esempio, 'm = self.m'? Non farebbe alcuna differenza in questo test, ma la mia versione di 'do_work()' è un ciclo che gira milioni di volte. –

5

I nomi locali sono più veloci perché Python fa dell'ottimizzazione che i nomi locali non hanno bisogno di accesso dict, d'altra parte, gli attributi di istanza devono accedere allo __dict__ dell'oggetto.

Questo è anche il motivo per cui i nomi locali sono più veloci dei nomi globali.

Problemi correlati