2012-09-13 10 views
8

Während ich versuchte, ein komplexeres Problem anzugehen, kam ich, um die Zugriffsgeschwindigkeit auf lokale Variable vs Member-Variablen zu vergleichen.Warum ist lokaler Variablenzugriff in Python schneller als der Zugriff auf Klassenmitglieder?

Hier ein Testprogramm:

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

weiß, dass ich es wie eine schlechte Idee aussehen könnte StressTestMember und StressTestLocal auf jeder Iteration zu instanziiert, aber es macht Sinn, in dem modellierten Programm, wo diese sind grundsätzlich aktive Datensätze.

Nach einer einfachen Benchmark

  • LOCAL Zugriffstest: 0m22.836
  • MEMBER Zugriffstest: 0m32.648s

Die lokale Version ~ 33% schneller ist, während immer noch ein Teil von eine Klasse. Warum?

Antwort

19

self.m += 1 bedeutet, dass Sie eine lokale Variable nachschlagen namens self und dann finden das Attribut m

Natürlich genannt, wenn Sie nur eine lokale Variable nachschlagen müssen, wird es ohne den zusätzlichen Schritt schneller.

Es kann hilfreich sein, zu schauen, was unter der Haube passiert:

>>> 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 Sehr gut, klare Antwort. – Tadeck

+0

sehr nett. Das verdient das Akzeptieren. –

+0

Also folgt daraus, dass es ratsam wäre, einen neuen Verweis auf eine Klassenvariable im lokalen Bereich zu erstellen? z. B. "m = selbst.m'? Es würde in diesem Test keinen Unterschied machen, aber meine Version von 'do_work()' ist eine Schleife, die millionenfach läuft. –

5

Lokale Namen sind schneller, da Python einige Optimierungen durchführt, dass lokale Namen keinen dict-Zugriff benötigen, auf der anderen Seite müssen Instanzattribute auf die des Objekts zugreifen.

Dies ist auch der Grund, warum lokale Namen schneller als globale Namen sind.

Verwandte Themen