Почему cProfile приводит к тому, что функции возвращают разные значения?

StackOverflow https://stackoverflow.com//questions/23041907

  •  21-12-2019
  •  | 
  •  

Вопрос

Я создаю модель на Python (3.3.1) для довольно простого, но сложного контракта с долгосрочными денежными потоками.Полная модель довольно сложна с точки зрения затрат времени, и поэтому я решил попробовать ее профилировать.Тем не менее, я получаю разные ответы с профилированием и без него.

Я сократил код до следующего примера:

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

Выходной сигнал:

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$ 

Есть ли простое объяснение, почему это каждый раз выдает разный ответ?Я ознакомился с руководством, но не вижу ничего очевидного.

Это было полезно?

Решение

Сначала я попытался воспроизвести с помощью python3 и, запустив "python3 scratch.py" и "python3 -m cProfile scratch.py", напечатал -20.7933...на моей машине.

Причина, по которой -20.0 возвращается в python 2.x, заключается в том, что оператор разделения "/" работал по-другому в python2.x (http://legacy.python.org/dev/peps/pep-0238/)

В python2 1/12 == 0

В python3 1/12 == 0.08333333....

Это означает, что в python2 строка

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

упрощает до

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

или

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

Вероятно, это не то, что вы предполагали.Интерпретация python3, вероятно, верна, а интерпретация python2 довольно бесполезна.В качестве дополнительного примечания, изменение (1/12) на (1.0 / 12) приводит к идентичному выводу как на python2, так и на python3 и заставит ваш код возвращать один и тот же результат с профилированием или без него, но это лечит симптом, а не причину.

Мое лучшее предположение относительно того, почему вы получаете разные выходные данные с профилированием и без него, заключается в том, что вы используете python3 без профилирования и python2 с профилированием.Использование одной и той же версии python при выполнении вашего кода с профилированием и без него важно для получения значимых результатов.

Тот факт, что вы используете ./scratch.py указывает на то, что у вас, вероятно, есть строка типа

#!/usr/bin/python3

вверху scratch.py (хотя это не включено в предоставленный код).Когда ты бежишь

./scratch.py

для выполнения файла используется /usr/bin/python3

Когда ты бежишь

python -m cProfile scratch.py

ваш интерпретатор python по умолчанию используется для выполнения файла (который, я предполагаю, является python2).

Если вы запустите "python" из командной строки (без каких-либо других аргументов), вы, вероятно, увидите, что intepreter по умолчанию равен 2.X.

Таким образом, заставить ваш код возвращать идентичные выходные данные с профилированием и без него должно быть так же просто, как указать python3 при профилировании:

 python3 -m cProfile scratch.py
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top