Pregunta

Estoy construyendo un modelo en Python (3.3.1) para un contrato bastante simple pero complicado con flujos de caja a largo plazo.El modelo completo es bastante complejo en términos de tiempo consumido y por eso decidí intentar perfilarlo.Sin embargo, obtengo respuestas diferentes con y sin elaboración de perfiles.

He reducido el código al siguiente ejemplo:

def generate_cashflows( income ):
    contingent_expense = [1000.0]
    income_cf = [income]
    outgo_cf = [ -0.001 * contingent_expense[0] ]
    bank = [ income_cf[0] + outgo_cf[0] ]

    for t in range(1, 20):
        contingent_expense.append(1000.0)
        income_cf.append( income )
        outgo_cf.append( -contingent_expense[t] * 0.001 )
        bank.append(    bank[t-1] * (1+0.05)**(1/12)
                + income_cf[t]
                + outgo_cf[t]
                )
    return bank[-1]

print(str(generate_cashflows(0)))

Producción:

calum@calum:~/pricing/model$ ./scratch.py 
-20.793337746348953
calum@calum:~/pricing/model$ python -m cProfile scratch.py
-20.0
     80 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.000    0.000 scratch.py:5(<module>)
    1    0.000    0.000    0.000    0.000 scratch.py:5(generate_cashflows)
   76    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    1    0.000    0.000    0.000    0.000 {range}


calum@calum:~/pricing/model$ 

¿Existe una explicación sencilla de por qué esto genera una respuesta diferente cada vez?He leído el manual pero no veo nada obvio.

¿Fue útil?

Solución

Primero, intenté reproducir con python3 y ejecutar "python3 scratch.py" y "python3 -m cProfile scratch.py" imprimen -20.7933...en mi máquina.

La razón por la que se devuelve -20.0 en Python 2.x es porque el operador de división "/" funcionó de manera diferente en Python2.x (http://legacy.python.org/dev/peps/pep-0238/)

En Python2, 1/12 == 0

En Python3, 1/12 == 0,08333333....

Eso significa que en python2 la línea

 bank.append(    bank[t-1] * (1+0.05)**(1/12)

simplifica a

 bank.append(    bank[t-1] * (1+0.05)**(0)

o

 bank.append(    bank[t-1] * 1

Probablemente esto no sea lo que pretendías.La interpretación de python3 probablemente sea correcta y la interpretación de python2 sea bastante inútil.Como nota al margen, cambiar (1/12) a (1.0/12) da como resultado un resultado idéntico tanto en python2 como en python3, y hará que su código devuelva el mismo resultado con o sin perfilado, pero eso es tratar el síntoma y no la causa. .

Mi mejor suposición de por qué obtienes diferentes resultados con y sin creación de perfiles es que estás usando python3 sin creación de perfiles y python2 con creación de perfiles.Usar la misma versión de Python cuando ejecuta su código con y sin creación de perfiles es esencial para obtener resultados significativos.

El hecho de que esté utilizando ./scratch.py ​​indica que probablemente tenga una línea como

#!/usr/bin/python3

en la parte superior de scratch.py ​​(aunque no está incluido en el código proporcionado).cuando corres

./scratch.py

/usr/bin/python3 se utiliza para ejecutar el archivo

cuando corres

python -m cProfile scratch.py

su intérprete de Python predeterminado se utiliza para ejecutar el archivo (que supongo que es python2)

Si ejecuta "python" desde la línea de comando (sin ningún otro argumento), probablemente verá que el intérprete predeterminado es 2.X.

Entonces, lograr que su código devuelva resultados idénticos con y sin perfilado debería ser tan simple como especificar python3 cuando crea el perfil:

 python3 -m cProfile scratch.py
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top