Что означают обратные кавычки для интерпретатора Python: `num`

88

Я играю с пониманием списков и наткнулся на этот небольшой фрагмент на другом сайте:

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).

Доминик Боу-Самра
источник
8
После прочтения «другого сайта» по адресу skymind.com/~ocrow/python_string у меня возник аналогичный вопрос, и я нашел эту страницу. Хороший вопрос и хороший ответ :)
netvope

Ответы:

123

Обратные кавычки - это устаревший псевдоним для repr() . Больше не используйте их, синтаксис был удален в Python 3.0.

Использование обратных кавычек кажется быстрее, чем использование repr(num)или num.__repr__()в версии 2.x. Я предполагаю, что это потому, что требуется дополнительный поиск в словаре в глобальном пространстве имен (для 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.

Фердинанд Бейер
источник
Хотел найти, как можно заменить обратные кавычки вызовом какой-то функции, но кажется, что это невозможно, или это так?
Jiri
2
Используйте repr () вместо обратных кавычек. Обратные кавычки являются устаревшим синтаксисом для repr () версии 3.0. На самом деле я предпочитаю использовать обратные кавычки, а не вызывать ДРУГОЙ функцию.
Доминик Боу-Самра
8
Причина, по которой обратные кавычки устарели, также связана с самим символом `; может быть трудно печатать (на некоторых клавиатурах), трудно понять, что это такое, трудно правильно печатать в книгах по Python. И т.д.
u0b34a0f6ae
4
@ kaizer.se: Спасибо, что указали на это. Вероятно, это основная причина отбрасывания обратных кавычек, см. Заявление Guidos в архивах списков рассылки: mail.python.org/pipermail/python-ideas/2007-January/000054.html
Фердинанд Бейер,
Первоначальный вопрос, который был опубликован, заключался в том, что я не мог найти обратные кавычки на моей клавиатуре;) Кажется, что ниже тильды после поиска в Google.
Доминик Боу-Самра
10

Использование обратных кавычек обычно бесполезно и отсутствует в Python 3.

Для чего это стоит:

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

для меня немного быстрее, чем версия с обратной кавычкой. Но беспокоиться об этом - вероятно, преждевременная оптимизация.

бобинс
источник
2
Зачем делать шаг назад и использовать карту вместо понимания списка / итератора?
nikow
4
На самом деле, 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)) )). Это немного разочаровывает ;-)
RedGlyph
8
Результат bobince меня не удивляет. Как показывает практика, неявные циклы в Python быстрее, чем явные, часто значительно быстрее. mapреализован в C с использованием цикла C, который намного быстрее, чем цикл Python, выполняемый на виртуальной машине.
Фердинанд Бейер
7
Не удивительно, это просто очень плохо для репутации списков (в этом примере - 30%). Но я предпочел бы иметь ясный, чем молниеносный код, если это не действительно важно, так что здесь нет ничего страшного. При этом функция map () не кажется мне непонятной, LC иногда переоценивают.
RedGlyph
4
mapкажется мне совершенно ясным и кратким, а я даже не знаю Python.
Zenexer 08
1

Я предполагаю, что numэто не определяет метод __str__(), поэтому str()необходимо выполнить второй поиск __repr__.

Обратные кавычки ищите напрямую __repr__. Если это правда, то использование repr()вместо обратных кавычек должно дать те же результаты.

Аарон Дигулла
источник