¿Qué significan las comillas invertidas para el intérprete de Python: `num`

88

Estoy jugando con listas por comprensión y encontré este pequeño fragmento en otro sitio:

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

Pasé unos minutos tratando de replicar la función (escribiendo) antes de darme cuenta de que la `num`broca la estaba rompiendo.

¿Qué hace incluir una declaración en esos caracteres? Por lo que puedo ver, es el equivalente de str (num). Pero cuando lo cronometré:

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

Tarda 4.09s mientras que:

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

tarda 2,43 s.

Ambos dan resultados idénticos, pero uno es mucho más lento. ¿Que esta pasando aqui?

EDITAR: Curiosamente ... repr()da resultados ligeramente más lentos que `num`. 2.99 vs 2.43s. Usando Python 2.6 (aún no he probado 3.0).

Dominic Bou-Samra
fuente
8
Después de leer "otro sitio" en skymind.com/~ocrow/python_string , tuve una pregunta similar y encontré esta página. Buena pregunta y buena respuesta :)
netvope

Respuestas:

123

Las comillas invertidas son un alias obsoleto para repr(). No los use más, la sintaxis se eliminó en Python 3.0.

Usar comillas invertidas parece ser más rápido que usar repr(num)o num.__repr__()en la versión 2.x. Supongo que se debe a que se requiere una búsqueda adicional en el diccionario en el espacio de nombres global (para repr) o en el espacio de nombres del objeto (para __repr__), respectivamente.


El uso del dismódulo prueba mi suposición:

def f1(a):
    return repr(a)

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

def f3(a):
    return `a`

Desmontaje muestra:

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

f1implica una búsqueda global de repr, f2una búsqueda de atributos __repr__, mientras que el operador de comillas invertidas se implementa en un código de operación separado. Dado que no hay sobrecarga para la búsqueda de diccionario ( LOAD_GLOBAL/ LOAD_ATTR) ni para las llamadas a funciones ( CALL_FUNCTION), las comillas invertidas son más rápidas.

Supongo que la gente de Python decidió que tener una operación separada de bajo nivel para repr()no vale la pena, y tener repr()comillas inversas y ambos viola el principio

"Debe haber una, y preferiblemente solo una, forma obvia de hacerlo"

por lo que la función se eliminó en Python 3.0.

Ferdinand Beyer
fuente
Quería encontrar cómo se pueden reemplazar las comillas invertidas con alguna llamada de función, pero parece que no es posible, ¿o no?
Jiri
2
Utilice repr () en lugar de comillas invertidas. Las comillas invertidas son sintaxis depreciada para repr () come 3.0. De hecho, prefiero el aspecto de las comillas invertidas en lugar de llamar a OTRA función.
Dominic Bou-Samra
8
La razón por la que las comillas invertidas están en desuso es también por el carácter `en sí mismo; puede ser difícil de escribir (en algunos teclados), difícil de ver qué es, difícil de imprimir correctamente en los libros de Python. Etc.
u0b34a0f6ae
4
@ kaizer.se: Gracias por señalarlo. Esta es probablemente la razón principal por la que se eliminan las comillas invertidas, consulte la declaración de Guidos en los archivos de la lista de correo: mail.python.org/pipermail/python-ideas/2007-January/000054.html
Ferdinand Beyer
La pregunta original que se publicó fue porque en realidad no pude encontrar comillas invertidas en mi teclado;) Debajo de la tilde parece después de buscar en Google.
Dominic Bou-Samra
10

Las comillas al revés generalmente no son útiles y desaparecieron en Python 3.

Por lo que vale, esto:

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

es un poco más rápido que la versión de comillas invertidas para mí. Pero preocuparse por esto probablemente sea una optimización prematura.

bobince
fuente
2
¿Por qué dar un paso atrás y usar map en lugar de listas / iteraciones por comprensión?
nikow
4
En realidad, timeitproduce resultados más rápidos para ''.join(map(repr, xrange(0, 1000000)))que para ''.join([repr(i) for i in xrange(0, 1000000)])(incluso peor para ''.join( (repr(i) for i in xrange(0, 1000000)) )). Es un poco decepcionante ;-)
RedGlyph
8
El resultado de Bobince no me sorprende. Como regla general, los bucles implícitos en Python son más rápidos que los explícitos, a menudo dramáticamente más rápidos. mapse implementa en C, usando un ciclo C, que es mucho más rápido que un ciclo Python ejecutado en la máquina virtual.
Ferdinand Beyer
7
Tampoco es de extrañar, es una lástima para la reputación de la lista por comprensión (con un 30% de acierto en este ejemplo). Pero prefiero tener un código claro que un código de alta velocidad a menos que esto sea realmente importante, así que no es gran cosa aquí. Dicho esto, la función map () no me parece confusa, las LC a veces están sobrevaloradas.
RedGlyph
4
mapme parece perfectamente claro y conciso, y ni siquiera conozco Python.
Zenexer
1

Supongo que eso numno define el método __str__(), por lo que str()tiene que hacer una segunda búsqueda __repr__.

Las comillas invertidas buscan directamente __repr__. Si eso es cierto, entonces usar en repr()lugar de las comillas inversas debería darle los mismos resultados.

Aaron Digulla
fuente