Nein, sie sind nicht genau gleichwertig , obwohl der Unterschied wahrscheinlich nicht signifikant ist.
class A(object):
const = 'abc'
def lengthy_op(self):
const = self.const
for i in xrange(AVOGADRO):
# do something which involves reading const
Dies schafft eine lokale Variable so dass jeder Zugriff von const die LOAD_FAST
Opcode verwenden.
const = 'abc'
class A(object):
def lengthy_op(self):
# global const
for i in xrange(AVOGADRO):
# do something which involves reading const
Dies, mit oder ohne redundante global const
verwendet LOAD_GLOBAL
den Wert der globalen Variablen für den Zugriff auf const
, xrange
und AVOGADRO
.
In C Python LOAD_GLOBAL
wird eine schnelle Wörterbuch-Lookup für den Zugriff auf die Variable (schnell, da die globalen Variablen in einem Wörterbuch mit nur String-Schlüssel und die Hash-Werte sind vorberechnet). Auf der anderen Seite greift LOAD_FAST
einfach auf die erste, zweite, dritte usw. lokale Variable zu, was eine Array-Indizierungsoperation ist.
Andere Versionen von Python (z. B. PyPy) können möglicherweise den Zugriff auf die globale Variable optimieren, wobei in diesem Fall möglicherweise kein Unterschied besteht.
Der erste Code (mit n=i+const
wie der Körper Loop) auseinanderbauen zu:
>>> dis.dis(A.lengthy_op)
5 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (const)
6 STORE_FAST 1 (const)
6 9 SETUP_LOOP 30 (to 42)
12 LOAD_GLOBAL 1 (xrange)
15 LOAD_GLOBAL 2 (AVOGADRO)
18 CALL_FUNCTION 1
21 GET_ITER
>> 22 FOR_ITER 16 (to 41)
25 STORE_FAST 2 (i)
8 28 LOAD_FAST 2 (i)
31 LOAD_FAST 1 (const)
34 BINARY_ADD
35 STORE_FAST 3 (n)
38 JUMP_ABSOLUTE 22
>> 41 POP_BLOCK
>> 42 LOAD_CONST 0 (None)
45 RETURN_VALUE
während der zweite Block gibt:
>>> dis.dis(A.lengthy_op)
5 0 SETUP_LOOP 30 (to 33)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (AVOGADRO)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 16 (to 32)
16 STORE_FAST 1 (i)
7 19 LOAD_FAST 1 (i)
22 LOAD_GLOBAL 2 (const)
25 BINARY_ADD
26 STORE_FAST 2 (n)
29 JUMP_ABSOLUTE 13
>> 32 POP_BLOCK
>> 33 LOAD_CONST 0 (None)
36 RETURN_VALUE
Python wird keine lokale Kopie der globalen machen, weil Es gibt keine einfache Möglichkeit, sicherzustellen, dass sich der globale Wert während der Ausführung des Codes nicht ändert. Alles, auch ein anderer Thread oder ein Debugger, könnte den Wert ändern, während die Schleife ausgeführt wird.
Wenn Sie Variable in Nur-Lese-Weise verwenden Sie Schlüsselwort global nicht brauchen. Ich würde erwarten, dass der Punktzugriff etwas langsamer ist, aber Antworten auf Fragen wie diese sind immer "Messen Sie es". Es ist sowieso nicht sehr wahrscheinlich ein Leistungsengpass. –
@Rogalski: Ich weiß, dass es nicht benötigt wird - meine Frage ist, ob es das globale im lokalen Bereich einreiht (es dem anderen äquivalent macht). Der Punktzugriff wird einmal und die globale Suche auch einmal durchgeführt - meine Frage ist, dass sie danach äquivalent sind - in der Schleife, wo in beiden Fällen nur der Name 'const' verwendet wird. Dies würde sofort von jemandem beantwortet werden, der den Bytecode erzeugen kann, nicht durch Messen, es sollte definitiv sein - außer wenn ich etwas vermisse ... –
Ich würde erwarten, dass der globale Zugriff langsamer ist, da der Variablenname zuerst gesucht wird in der Symboltabelle des lokalen Bereichs, und in der globalen nur, wenn nichts gefunden wird – Ilja