0

I am struggling to understand why this function apparently fails in the Jupyter Notebook, but not in the IPython shell:

def present_value( r, n, fv = None, pmt = None ):
    '''
    Function to compute the Present Value based on interest rate and 
    a given future value. 

    Arguments accepted
    ------------------
       *   r = interest rate,
               which should be given in its original percentage, eg. 
               5% instead of 0.05

       *   n = number of periods for which the cash flow,
               either as annuity or single flow from one present value

       *  fv = future value in dollars,
               if problem is annuity based, leave this empty

       * pmt = each annuity payment in dollars,
               if problem is single cash flow based, leave this empty
    '''
    original_args = [r, n, fv, pmt]
    dec_args      = [Decimal( arg ) if arg != None
                                  else arg
                                  for  arg in original_args
                                  ]
    if dec_args[3] == None:
        return dec_args[2] / ( ( 1 + ( dec_args[0] / 100 ) )**dec_args[1] )

    elif dec_args[2] == None:
        #                     annuity_length = range( 1, dec_args[1] + 1 )
        #                     Not allowed to add a Decimal object
        #                     with an integer and to use it
        #                     in the range() function,
        #                     so we dereference the integer from original_args
        annuity_length = range( 1, original_args[1] + 1 )
        #                     Apply discounting to each annuity payment made
        #                     according to number of years left till end
        all_compounded_pmt = [dec_args[3] * ( 1 / ( ( 1 + dec_args[0] / 100 ) ** time_left ) ) \
                              for time_left in annuity_length
                              ]
        return sum( all_compounded_pmt )

When I imported the module that this function resides in, named functions.py, using from functions import *, and then executed present_value(r=7, n=35, pmt = 11000), I got the error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-93-c1cc587f7e27> in <module>()
----> 1 present_value(r=7, n=35, pmt = 11000)

/path_to_file/functions.py in present_value(r, n, fv, pmt)
     73     if dec_args[3] == None:
     74         return dec_args[2]/((1 + (dec_args[0]/100))**dec_args[1])
---> 75 
     76     elif dec_args[2] == None:
     77 #        annuity_length = range(1, dec_args[1]+1)

TypeError: 'decimal.Decimal' object cannot be interpreted as an integer

but in the IPython shell, evaluating this function it works perfectly fine:

In [42]: functions.present_value(r=7, n=35, pmt = 11000)
Out[42]: Decimal('142424.39530474029537')

Can anyone please help me with this really confusing and obscure issue?

user3666197
  • 1
  • 6
  • 50
  • 92
AKKA
  • 165
  • 4
  • 15
  • IIRC you figured it out by restarting the kernel right ? – Matt Mar 16 '17 at 19:56
  • Yes with a big help from the people who helped me when I posted this on the IPython Github: https://github.com/ipython/ipython/issues/10367 – AKKA Mar 22 '17 at 09:01
  • Does inserting an `imp.reload()` into the IPython notebook or something similar help allow me to not restart the kernel? What's a good practice? – AKKA Mar 22 '17 at 09:03
  • It depends. And it may even depends on your version of Python. Modules are not supposed to be reloadable, but for most of them it works. That's the "We are between adults" philosophy of Python. If you want to go crazy and try imp.reload(), it may work, if it doesn't then it's not really a bug. – Matt Mar 22 '17 at 16:46

0 Answers0