我正在尝试列表理解,我在另一个网站上发现了这个小片段:
return ''.join([`num` for num in xrange(loop_count)])
我花了几分钟尝试复制该功能(通过键入),然后才意识到
`num`
位破坏了它。
在这些字符中包含一个声明有什么作用?据我所知,它相当于 str(num)。但当我计时时:
return ''.join([str(num) for num in xrange(10000000)])
需要 4.09 秒,而:
return ''.join([`num` for num in xrange(10000000)])
需要 2.43 秒。
两者都给出相同的结果,但其中一个要慢得多。这是怎么回事?
奇怪...
repr()
给出的结果比 `num`
稍慢。 2.99 秒 vs 2.43 秒。我正在使用Python 2.6(还没有尝试过3.0)。
反引号是
repr()
的已弃用别名。不要再使用它们; Python 3.0 中删除了该语法。
在 2.x 版本中,使用反引号似乎比使用
repr(num)
或 num.__repr__()
更快。我猜这是因为在全局命名空间(对于repr
)或对象的命名空间(对于__repr__
)中分别需要额外的字典查找。
使用
dis
模块证明了我的假设:
def f1(a):
return repr(a)
def f2(a):
return a.__repr__()
def f3(a):
return `a`
拆解展示:
>>> import dis
>>> dis.dis(f1)
3 0 LOAD_GLOBAL 0 (repr)
3 LOAD_FAST 0 (a)
6 CALL_FUNCTION 1
9 RETURN_VALUE
>>> dis.dis(f2)
6 0 LOAD_FAST 0 (a)
3 LOAD_ATTR 0 (__repr__)
6 CALL_FUNCTION 0
9 RETURN_VALUE
>>> dis.dis(f3)
9 0 LOAD_FAST 0 (a)
3 UNARY_CONVERT
4 RETURN_VALUE
f1
涉及对repr
的全局查找,f2
对__repr__
的属性查找,而反引号运算符是在单独的操作码中实现的。由于字典查找 (LOAD_GLOBAL
/LOAD_ATTR
) 和函数调用 (CALL_FUNCTION
) 都没有开销,因此反引号更快。
我猜Python人员认为对
repr()
进行单独的低级操作是不值得的,并且同时使用 repr()
和反引号违反了原则
“应该有一种——最好只有一种——明显的方法来做到这一点”
因此该功能在 Python 3.0 中被删除。
反引号通常没有用,在 Python 3 中已经消失了。
对于它的价值来说,这个:
''.join(map(repr, xrange(10000000)))
对我来说比反引号版本稍微快一些。但担心这一点可能是一个不成熟的优化。
我的猜测是
num
没有定义方法 __str__()
,因此 str()
必须对 __repr__
进行第二次查找。
反引号直接查找
__repr__
。如果这是真的,那么使用 repr()
而不是反引号应该会得到相同的结果。
Python 3 开发人员应该向 Javascript 设计者学习,他们使用反引号作为第三种不同类型的引号(除了单引号和双引号之外),并且还可以使用快速字符串,而不需要前面的“f”。这样我们就可以对字符串执行 `Hello, {username}`,对字节执行 b`Hello, {username}`。