Python 内部原理
跳转到导航
跳转到搜索
寻找全局变量
在函数定义时,函数的代码对象被初始化一个 co_names 属性(即 func.__code__.co_names ,保存了函数中全局变量的名字。函数另有 __globals__ 属性指向 globals() 所返回的那个字典。和 globals() 函数一样,这是函数定义的地方的全局变量表,而非被调用的地方者。因此,在 exec() 中调用的函数并不会使用在 exec() 调用时传递进去的全局变量表。[1]
在函数中含有 exec 调用时,解释器将使用 LOAD_NAME 指令取代 LOAD_GLOBAL 指令,以寻找在 exec 中生成的局部变量。
性能
字符串处理
连接多个字符串, str.join 效率比直接相加略高(在没有编译期优化的情况下)(Python 3.3):
In [1]: a = 'a'
In [2]: %timeit a + 'b' + 'c' + 'd'
1000000 loops, best of 3: 371 ns per loop
In [3]: %timeit '%s%s%s%s' % (a, 'b', 'c', 'd')
1000000 loops, best of 3: 506 ns per loop
In [4]: %timeit ''.join((a, 'b', 'c', 'd'))
1000000 loops, best of 3: 348 ns per loop
正则
在进行大量项目的正则替换时,如果匹配项较少,先做子串判断可以更快(Python 3.3):
import re
pkgrel_re = re.compile(r'^\s*pkgrel=(\d+)')
def plus_one(m):
s = m.group()
return s[:m.start(1)] + str(int(m.group(1))+1) + s[m.end(1):]
def a(l):
if 'pkgrel' in l:
l = pkgrel_re.sub(plus_one, l)
return l
def b(l):
l = pkgrel_re.sub(plus_one, l)
return l
In [4]: %timeit a('this is only a test line')
1000000 loops, best of 3: 276 ns per loop
In [5]: %timeit b('this is only a test line')
100000 loops, best of 3: 2.77 µs per loop
In [6]: %timeit a('pkgrel=4 # test')
100000 loops, best of 3: 8.73 µs per loop
In [7]: %timeit b('pkgrel=4 # test')
100000 loops, best of 3: 8.37 µs per loop
PyPy 2.1beta1-2 (Python 3) 版差异较小:
In [16]: %timeit a('this is only a test line')
10000000 loops, best of 3: 21.6 ns per loop
In [17]: %timeit b('this is only a test line')
1000000 loops, best of 3: 618 ns per loop
In [18]: %timeit a('pkgrel=4 # test')
100000 loops, best of 3: 4.16 µs per loop
In [19]: %timeit b('pkgrel=4 # test')
100000 loops, best of 3: 4.19 µs per loop
列表处理
(Python 3 中)向列表末尾添加两个数据时, .append 比 .extend 列表要快,但是比 .extend tuple 慢不少。如果数据多于两个,则 .extend 总是更快:
In [1]: timeit a = [1]; a.append(2); a.append(3)
1000000 loops, best of 3: 457 ns per loop
In [2]: timeit a = [1]; a.extend([2,3])
1000000 loops, best of 3: 470 ns per loop
In [3]: timeit a = [1]; a.extend((2,3))
1000000 loops, best of 3: 328 ns per loop
In [4]: timeit a = [1]; a.append(2); a.append(3); a.append(4)
1000000 loops, best of 3: 576 ns per loop
In [5]: timeit a = [1]; a.extend([2,3,4])
1000000 loops, best of 3: 494 ns per loop
In [6]: timeit a = [1]; a.extend((2,3,4))
1000000 loops, best of 3: 334 ns per loop
JSON 序列化
对于很简单的字典,使用 CPython 3.3.2:
one k-v: bson: 6.48 µs per loop json: 15.6 µs per loop ujson: 1.39 µs per loop tornado: 16.2 µs per loop
four k-v's: bson: 7.98 µs per loop json: 18 µs per loop ujson: 2.28 µs per loop tornado: 18.4 µs per loop
空间大小差异不大
编译期优化
多个字面字符串相加、字面数值计算会有优化。如以下计算均有优化(Python 3.3、Python 2.7):
a = 4 * 8
return 5 * 8 * a
但是以下则没有:
return a * 5 * 8
在 Python 3.3 中,观察到以下优化:
>>> import dis
>>> def t():
... return '%s%s%s%s' % ('a', 'b', 'c', 'd')
...
>>> dis.dis(t)
2 0 LOAD_CONST 7 ('abcd')
3 RETURN_VALUE
Python 2.7 中没有这种优化。如果参与格式化的对象中包含变量亦不会优化。
参见
外部链接
- The Performance Impact of Using dict() Instead of {} in CPython 2.7 - Doug Hellmann
- PYC文件格式分析 — KDr2's Personal Website
- Pickle——基于栈的编程语言
工具
- uncompyle2, A Python 2.5, 2.6, 2.7 byte-code decompiler, written in Python 2.7.