لماذا يتسبب cProfile في قيام الوظائف بإرجاع قيم مختلفة؟

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

  •  21-12-2019
  •  | 
  •  

سؤال

أقوم ببناء نموذج في بايثون (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خدش.py" و"python3 -m cProfileخدش.py" كلاهما يطبعان -20.7933...على الجهاز الخاص بي.

السبب وراء إرجاع -20.0 على python 2.x هو أن عامل القسمة "/" يعمل بشكل مختلف في python2.x (http://legacy.python.org/dev/peps/pep-0238/)

في بايثون2، 1/12 == 0

في بيثون3، 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

في الجزء العلوي منcratch.py ​​(على الرغم من عدم تضمينه في الكود المقدم).عند تشغيل

./scratch.py

يتم استخدام /usr/bin/python3 لتنفيذ الملف

عند تشغيل

python -m cProfile scratch.py

يتم استخدام مترجم python الافتراضي الخاص بك لتنفيذ الملف (والذي أعتقد أنه python2)

إذا قمت بتشغيل "python" من سطر الأوامر (بدون أي وسيطات أخرى) فمن المحتمل أن ترى أن المترجم الافتراضي هو 2.X.

لذا فإن الحصول على الكود الخاص بك لإرجاع مخرجات متطابقة مع وبدون ملف تعريف يجب أن يكون بسيطًا مثل تحديد python3 عند إنشاء ملف تعريف:

 python3 -m cProfile scratch.py
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top