Что означают обратные кавычки для интерпретатора 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()вместо обратных кавычек должно дать те же результаты.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.