python performance python-internals

python - ¿Por qué es repr(int) más rápido que str(int)?



performance python-internals (3)

Me pregunto por qué repr(int) es más rápido que str(int) . Con el siguiente fragmento de código:

ROUNDS = 10000 def concat_strings_str(): return ''''.join(map(str, range(ROUNDS))) def concat_strings_repr(): return ''''.join(map(repr, range(ROUNDS))) %timeit concat_strings_str() %timeit concat_strings_repr()

Obtengo estos tiempos (Python 3.5.2, pero resultados muy similares con 2.7.12):

1.9 ms ± 17.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 1.38 ms ± 9.07 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Si estoy en el camino correcto, se llama a la misma función long_to_decimal_string debajo del capó.

¿Obtuve algo mal o qué más está pasando que me estoy perdiendo?

actualización : Esto probablemente no tiene nada que ver con los métodos __repr__ o __str__ int , pero con las diferencias entre repr() y str() , ya que int.__str__ e int.__repr__ son, de hecho, int.__repr__ rápidos:

def concat_strings_str(): return ''''.join([one.__str__() for one in range(ROUNDS)]) def concat_strings_repr(): return ''''.join([one.__repr__() for one in range(ROUNDS)]) %timeit concat_strings_str() %timeit concat_strings_repr()

resultados en:

2.02 ms ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 2.05 ms ± 7.07 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


Acabo de comparar las implementaciones str y repr en la rama 3.5. Mira here .

Parece que hay más controles en str :


Debido a que el uso de str(obj) primero debe pasar por type.__call__ then str.__new__ (crea una nueva cadena) luego PyObject_Str ( PyObject_Str una cadena fuera del objeto) que invoca int.__str__ y, finalmente , utiliza la función que has vinculado.

repr(obj) , que corresponde a builtin_repr , llama directamente a PyObject_Repr (obtiene el objeto repr) que luego llama a int.__repr__ que usa la misma función que int.__str__ .

Además, la ruta que toman a través de call_function (la función que maneja el CALL_FUNCTION operación CALL_FUNCTION que se genera para las llamadas) es ligeramente diferente.

Desde la rama principal en GitHub (CPython 3.7):

Como dice su actualización, esto no se trata de int.__repr__ vs int.__str__ , son la misma función después de todo; se trata de cómo repr y str llegan a ellos. str solo necesita trabajar un poco más duro.


Hay varias posibilidades porque las funciones CPython que son responsables del str y repr return son ligeramente diferentes.

Pero supongo que la razón principal es que str es un type (una clase) y el método str.__new__ tiene que llamar a __str__ mientras que repr puede ir directamente a __repr__ .