What do backticks mean to the Python interpreter? Example: `num`

Question:

I’m playing around with list comprehensions and I came across this little snippet on another site:

return ''.join([`num` for num in xrange(loop_count)])

I spent a few minutes trying to replicate the function (by typing) before realising the `num` bit was breaking it.

What does enclosing a statement in those characters do? From what I can see it is the equivalent of str(num). But when I timed it:

return ''.join([str(num) for num in xrange(10000000)])

It takes 4.09 seconds whereas:

return ''.join([`num` for num in xrange(10000000)])

takes 2.43 seconds.

Both give identical results, but one is a lot slower. What is going on here?

Oddly… repr() gives slightly slower results than `num`. 2.99 seconds vs 2.43 seconds. I am using Python 2.6 (haven’t tried 3.0 yet).

Asked By: Dominic Bou-Samra

||

Answers:

Backticks are a deprecated alias for repr(). Don’t use them any more; the syntax was removed in Python 3.0.

Using backticks seems to be faster than using repr(num) or num.__repr__() in version 2.x. I guess it’s because additional dictionary lookup is required in the global namespace (for repr), or in the object’s namespace (for __repr__), respectively.


Using the dis module proves my assumption:

def f1(a):
    return repr(a)

def f2(a):
    return a.__repr__()

def f3(a):
    return `a`

Disassembling shows:

>>> 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 involves a global lookup for repr, f2 an attribute lookup for __repr__, whereas the backtick operator is implemented in a separate opcode. Since there is no overhead for dictionary lookup (LOAD_GLOBAL/LOAD_ATTR) nor for function calls (CALL_FUNCTION), backticks are faster.

I guess that the Python folks decided that having a separate low-level operation for repr() is not worth it, and having both repr() and backticks violates the principle

"There should be one– and preferably only one –obvious way to do it"

so the feature was removed in Python 3.0.

Answered By: Ferdinand Beyer

My guess is that num doesn’t define the method __str__(), so str() has to do a second lookup for __repr__.

The backticks look directly for __repr__. If that’s true, then using repr() instead of the backticks should give you the same results.

Answered By: Aaron Digulla

Backtick quoting is generally non-useful and is gone in Python 3.

For what it’s worth, this:

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

is marginally faster than the backtick version for me. But worrying about this is probably a premature optimisation.

Answered By: bobince
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.