Що означають зворотні позначки для інтерпретатора python: `num`


87

Я пограюсь із розумінням списку, і я натрапив на цей маленький фрагмент на іншому сайті:

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

Обидва дають однакові результати, але один набагато повільніше. Що тут відбувається?

EDIT: Як не дивно ... repr()дає трохи повільніші результати, ніж `num`. 2.99 с проти 2.43 с. Використання Python 2.6 (ще не пробував 3.0).


8
Прочитавши "інший сайт" на сайті skymind.com/~ocrow/python_string , у мене виникло подібне запитання і я знайшов цю сторінку. Гарне запитання та приємна відповідь :)
netvope

Відповіді:


122

Зворотні посилання є застарілим псевдонімом для 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.


Я хотів знайти, як ви можете замінити зворотні посилання якимось викликом функції, але, здається, це неможливо, чи це можливо?
Іржі

2
Використовуйте repr () замість зворотних посилань. Зворотні посилання є амортизованим синтаксисом для repr () come 3.0. Я насправді віддаю перевагу вигляду зворотних ліній, а не виклику ДРУГОЇ функції.
Домінік Бу-Самра

8
Причина застарілих зворотних посилань також пов’язана з самим символом `; це може бути важко друкувати (на деяких клавіатурах), важко зрозуміти, що це таке, важко правильно друкувати в книгах на Python. І т. Д.
u0b34a0f6ae

4
@ kaizer.se: Дякую, що вказали на це. Це, мабуть, основна причина відмови від зворотних міток, див. Заяву Guidos в архіві списків розсилки: mail.python.org/pipermail/python-ideas/2007-January/000054.html
Фердинанд Бейер,

Оригінальне запитання, яке це було опубліковано, було тому, що я насправді не міг знайти зворотні позначки на своїй клавіатурі;) Нижче тильди це здається після гуглиння.
Домінік Бу-Самра

10

Зворотне цитування, як правило, є корисним, і в Python 3 його немає.

Для чого це варто, це:

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

для мене незначно швидший, ніж версія backtick. Але турбуватися про це, можливо, передчасна оптимізація.


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

1

Я припускаю, що numце не визначає метод __str__(), тому str()доводиться робити другий пошук для __repr__.

Зворотні позначки шукають безпосередньо __repr__. Якщо це правда, то використання repr()замість зворотних посилань має дати ті самі результати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.