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).
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With