【问题标题】:What do backticks mean to the python interpreter: `num`反引号对 python 解释器意味着什么:`num`
【发布时间】:2010-12-12 23:37:50
【问题描述】:

我正在玩列表推导,我在另一个网站上遇到了这个小 sn-p:

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 秒与 2.43 秒。使用 Python 2.6(尚未尝试 3.0)。

【问题讨论】:

标签: python list-comprehension


【解决方案1】:

反引号是 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 涉及对reprf2 的全局查找以及对__repr__ 的属性查找,而反引号运算符在单独的操作码中实现。由于字典查找 (LOAD_GLOBAL/LOAD_ATTR) 和函数调用 (CALL_FUNCTION) 没有开销,因此反引号更快。

我猜 Python 人认为对 repr() 进行单独的低级操作是不值得的,并且同时使用 repr() 和反引号违反了原则

“应该有一种——最好只有一种——明显的方法”

所以这个特性在 Python 3.0 中被移除了。

【讨论】:

  • 我想找到,如何用一些函数调用替换反引号,但似乎不可能,或者是吗?
  • 使用 repr() 代替反引号。反引号是 repr() 3.0 版本的贬值语法。我实际上更喜欢反引号的外观,而不是调用另一个函数。
  • 不推荐使用反引号的原因也是因为 ` 字符本身;它可能很难输入(在某些键盘上),很难看清它是什么,很难在 Python 书籍中正确打印。等等。
  • @kaizer.se:感谢您指出这一点。这可能是放弃反引号的主要原因,请参阅邮件列表档案中的 Guidos 声明:mail.python.org/pipermail/python-ideas/2007-January/000054.html
  • 最初发布的问题是因为我实际上在键盘上找不到反引号;)在谷歌搜索后似乎在波浪号下方。
【解决方案2】:

我的猜测是num 没有定义方法__str__(),所以str() 必须对__repr__ 进行第二次查找。

反引号直接查找__repr__。如果这是真的,那么使用 repr() 而不是反引号应该会得到相同的结果。

【讨论】:

    【解决方案3】:

    反引号通常没有用,并且在 Python 3 中消失了。

    为了它的价值,这个:

    ''.join(map(repr, xrange(10000000)))
    

    对我来说比反引号版本快一点。但担心这一点可能是过早的优化。

    【讨论】:

    • 为什么要倒退一步并使用 map 而不是列表/迭代器推导?
    • 实际上,timeit''.join(map(repr, xrange(0, 1000000))) 生成的结果比''.join([repr(i) for i in xrange(0, 1000000)]) 更快(''.join( (repr(i) for i in xrange(0, 1000000)) ) 更糟)。这有点令人失望;-)
    • bobince 的结果对我来说并不奇怪。根据经验,Python 中的隐式循环比显式循环快,而且通常快得多。 map 用 C 语言实现,使用 C 循环,比在虚拟机中执行的 Python 循环快得多。
    • 也不奇怪,这对于列表推导的声誉来说太糟糕了(在这个例子中命中率为 30%)。但我宁愿有清晰的代码而不是超快的代码,除非这真的很重要,所以这里没什么大不了的。话虽如此,map() 函数并没有让我觉得不清楚,LC 有时被高估了。
    • map 对我来说似乎非常清晰简洁,而我什至不懂 Python。
    猜你喜欢
    • 1970-01-01
    • 2014-02-23
    • 2018-04-21
    • 1970-01-01
    • 2016-07-28
    • 2020-01-08
    • 1970-01-01
    • 2020-05-11
    • 1970-01-01
    相关资源
    最近更新 更多