这两个完全等同于性能(即,生成的代码完全等效):
class A(object):
const = 'abc'
def lengthy_op(self):
const = self.const
for i in xrange(AVOGADRO):
# do something which involves reading const
和
const = 'abc'
class A(object):
def lengthy_op(self):
global const
for i in xrange(AVOGADRO):
# do something which involves reading const
答案 0 :(得分:1)
不,他们不是完全等同,虽然差异不大可能。
class A(object):
const = 'abc'
def lengthy_op(self):
const = self.const
for i in xrange(AVOGADRO):
# do something which involves reading const
这会创建一个局部变量,因此const的任何访问都将使用LOAD_FAST
操作码。
const = 'abc'
class A(object):
def lengthy_op(self):
# global const
for i in xrange(AVOGADRO):
# do something which involves reading const
有或没有冗余global const
使用LOAD_GLOBAL
来访问全局变量const
,xrange
和AVOGADRO
的值。
在C中,Python LOAD_GLOBAL
将执行快速字典查找以访问变量(快速,因为全局变量只使用字符串键在字典中,并且哈希值是预先计算的)。另一方面,LOAD_FAST
只是访问第一个,第二个,第三个等局部变量,这是一个数组索引操作。
其他版本的Python(例如PyPy)可能能够优化访问全局变量,在这种情况下可能没有任何差异。
第一个代码(n=i+const
作为循环体)反汇编为:
>>> 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
而第二个块给出:
>>> 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不会制作全局的本地副本,因为没有简单的方法可以确保在代码运行时全局值不会发生变化。任何东西,甚至是另一个线程或调试器,都可以在循环执行时修改该值。
答案 1 :(得分:0)
实际上是更快还是更慢取决于您的范围,范围存储在字典中,字典越小(访问速度越快)。由于字典被实现为散列集,因此查找性能为O(1)。
每当您尝试访问变量时,Python都会按以下顺序遍历范围:
globals()
访问)list
,int
等。访问函数/类属性的工作方式与此类似,但涉及:
__getattribute__
__dict__
__getattr__
这也是所有继承类的。
Duncan完全回答了你的其余问题