您现在的位置: 主页 > 上位机技术 > python > Python中,代码放在函数中运行为什么比放在全局中运行快?
本文所属标签:
为本文创立个标签吧:

Python中,代码放在函数中运行为什么比放在全局中运行快?

来源:网络整理 网络用户发布,如有版权联系网管删除 2018-08-13 

因为CPython的解释器实现细节。
CPython的解释器,对局部变量是用数组存储,用下标来访问;而对全局变量是用dict来存储,用符号(symbol)来做hash访问。速度差距是杠杠的。
这是因为一旦函数定义好之后,局部变量的个数就不能改了,所以可以用固定大小的容器存储;而全局名字是可以一边执行一边改变的,所以得用更动态的方式来存储。

看CPython的字节码的 LOAD_FAST 与 LOAD_GLOBAL 就可以看出差异了 ^_^

对上面的描述觉得迷惑的同学,可以先参考一些背景资料:有没有内容类似于《Python源码剖析》,但内容更新过,针对新版本的Python书籍? - RednaxelaFX 的回答
特别是其中用Python实现的教学用CPython字节码解释器的例子:
A Python Interpreter Written in Python(其代码在 byterun/pyvm2.py at master nedbat/byterun GitHub
这个用Python实现的解释器其中就有这里提到的读写局部变量用的 LOAD_FAST / STORE_FAST 指令的实现但为了简单起见,它实现这两条字节码指令是用 dict 来存储数据的,而不是像真正的CPython那样用数组来存储。其实稍微改改这个Python代码就可以让它在这方面更接近CPython的样子了。

===========================================

评论区有同学提到 locals(),这在正常Python里是改变不了实际局部变量的状态的喔:

$ python
Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo():
...   a = 1
...   b = 2
...   locals()['a'] = 42
...   print(a, b)
... 
>>> foo()
(1, 2)
>>> import dis
>>> dis.dis(foo)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

  3           6 LOAD_CONST               2 (2)
              9 STORE_FAST               1 (b)

  4          12 LOAD_CONST               3 (42)
             15 LOAD_GLOBAL              0 (locals)
             18 CALL_FUNCTION            0
             21 LOAD_CONST               4 ('a')
             24 STORE_SUBSCR        

  5          25 LOAD_FAST                0 (a)
             28 LOAD_FAST                1 (b)
             31 BUILD_TUPLE              2
             34 PRINT_ITEM          
             35 PRINT_NEWLINE       
             36 LOAD_CONST               0 (None)
             39 RETURN_VALUE

然后也有提到exec / eval的:
>>> def bar():
...   a = 1
...   b = 2
...   exec('c = 3')
...   print(a, b, c)
...   print(locals())
... 
>>> bar()
(1, 2, 3)
{'a': 1, 'c': 3, 'b': 2}
>>> dis.dis(bar)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

  3           6 LOAD_CONST               2 (2)
              9 STORE_FAST               1 (b)

  4          12 LOAD_CONST               3 ('c = 3')
             15 LOAD_CONST               0 (None)
             18 DUP_TOP             
             19 EXEC_STMT           

  5          20 LOAD_FAST                0 (a)
             23 LOAD_FAST                1 (b)
             26 LOAD_NAME                0 (c)
             29 BUILD_TUPLE              3
             32 PRINT_ITEM          
             33 PRINT_NEWLINE       

  6          34 LOAD_NAME                1 (locals)
             37 CALL_FUNCTION            0
             40 PRINT_ITEM          
             41 PRINT_NEWLINE       
             42 LOAD_CONST               0 (None)
             45 RETURN_VALUE
注意这里“局部变量”c是在一个exec语句(Python 3的话是exec()函数)里动态定义的,而在exec语句后对c的使用就用的是LOAD_NAME字节码而不是普通局部变量用的LOAD_FAST这说明了动态定义的局部变量与普通局部变量的差异,而前面说“局部变量的个数不会改变”不包括这种动态定义的情况。

              查看评论 回复



嵌入式交流网主页 > 上位机技术 > python > Python中,代码放在函数中运行为什么比放在全局中运行快?
 变量 存储 局部

"Python中,代码放在函数中运行为什么比放在全局中运行快?"的相关文章

网站地图

围观()