Domanda

Sto costruendo un modello in Python (3.3.1) per un contratto abbastanza semplice ma complicato con flussi di cassa a lungo termine.Il modello completo è abbastanza complesso in termini di tempo impiegato e quindi ho deciso di provare a profilarlo.Tuttavia, ricevo risposte diverse con e senza profilazione.

Ho ridotto il codice al seguente esempio:

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

Produzione:

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$ 

C'è una spiegazione semplice del motivo per cui questo produce una risposta diversa ogni volta?Ho letto il manuale ma non vedo nulla di evidente.

È stato utile?

Soluzione

Innanzitutto, ho tentato di riprodurlo con python3 e eseguendo "python3 scratch.py" e "python3 -m cProfile scratch.py" entrambi stampano -20.7933...sulla mia macchina.

Il motivo per cui -20.0 viene restituito su python 2.x è perché l'operatore di divisione "/" funzionava diversamente in python2.x (http://legacy.python.org/dev/peps/pep-0238/)

In Python2, 1/12 == 0

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

Ciò significa che in python2 la linea

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

semplifica a

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

O

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

Probabilmente non è quello che volevi.L'interpretazione di python3 è probabilmente corretta e l'interpretazione di python2 è abbastanza inutile.Come nota a margine, la modifica da (1/12) a (1.0/12) si traduce in un output identico sia su python2 che su python3 e farà sì che il codice restituisca lo stesso output con o senza profilazione, ma questo tratta il sintomo e non la causa .

La mia ipotesi migliore sul motivo per cui ottieni risultati diversi con e senza profilazione è che stai utilizzando python3 senza profilazione e python2 con profilazione.Utilizzare la stessa versione di Python quando si esegue il codice con e senza profilazione è essenziale per ottenere risultati significativi.

Il fatto che tu stia utilizzando ./scratch.py ​​indica che probabilmente hai una riga simile

#!/usr/bin/python3

nella parte superiore di scratch.py ​​(sebbene non sia incluso nel codice fornito).Quando corri

./scratch.py

/usr/bin/python3 viene utilizzato per eseguire il file

Quando corri

python -m cProfile scratch.py

il tuo interprete Python predefinito viene utilizzato per eseguire il file (che immagino sia python2)

Se esegui "python" dalla riga di comando (senza altri argomenti) probabilmente vedrai che l'interprete predefinito è 2.X.

Quindi fare in modo che il tuo codice restituisca un output identico con e senza profilazione dovrebbe essere semplice come specificare python3 durante la profilazione:

 python3 -m cProfile scratch.py
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top