2

I have the following example in my book, which is supposed to be a program whch calculates the new balance after interest is added on multiple accounts:

def addInterest(balances, rate):
    for i in range (len(balances)):
    balances[i] = balances[i] * (1 + rate)


def test():
    amounts = [1000, 2200, 800, 360]
    rate = 0.05
    addInterest(amounts, rate)
    print(amounts)


test()

The output is [1050.0, 2310.0, 840.0, 378.0]

There is no return call at the end of addInterest, so why doesn't print(amounts) just print amounts which was defined intially, namely [1000, 2200, 800, 360]?

Ovi
  • 573
  • 2
  • 5
  • 16
  • What is the given output? What is the given return? – Malik Brahimi Jul 15 '15 at 19:01
  • @MalikBrahimi Sorry I just added the output of the program – Ovi Jul 15 '15 at 19:02
  • I don't get it. You printed the result, what is the problem? – Malik Brahimi Jul 15 '15 at 19:02
  • 6
    This is not an example of returning a value. Lists are mutable [see explanation here](https://docs.python.org/2/reference/datamodel.html) so when you call the function `addInterest`, it _actually changes_ the values in `amounts`. The changed value is what gets printed – krethika Jul 15 '15 at 19:02
  • @MalikBrahimi I don't understand why the output isn't [1000, 2200, 800, 360], because there is no call for return in addInterest – Ovi Jul 15 '15 at 19:03
  • Because you index the function and reassign the value at the given index. – Malik Brahimi Jul 15 '15 at 19:07
  • 1
    Python arguments are [pass by (object) reference](http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/) – Bryce Guinta Jul 15 '15 at 19:10

4 Answers4

2

Indeed, when no return is specified, None is returned by default. But, why are you getting other values? Because when you do this

balances[i] = balances[i] * (1 + rate)

you are modifying the values of the list balances.

So, you are doing the following:

  1. Declare the list amounts = [1000, 2200, 800, 360]
  2. Call the function addInterest passing the list as a parameter. Inside this function you are modifying the content of this list. You don't return anything, but the list is already modified.
  3. You print the modified list and the new values are shown.
Christian Tapia
  • 33,620
  • 7
  • 56
  • 73
  • But if amounts was just defined as a number, (i.e. amounts = 1000) then the print statement would display 1000, not 1050 – Ovi Jul 15 '15 at 19:07
  • Note that between the definition and the `print` there is a call to `addInterests`. You are passing your list `amount` to `addInterests` and in this function this list is modified. Finally, when you reach the `print` the list `amount` has the new values. – Christian Tapia Jul 15 '15 at 19:11
  • @so if amount is a mutable object, the print statement would show the modified amount; and if amount is a non-mutable object, then the print statement would show the non-modified ammount? – Ovi Jul 15 '15 at 19:16
  • The `print` statement just prints the content, nothing else. What matters here is if you modify the object or not. In this case, a `list` is mutable, but for example, a `tuple` isn't. You won't be able to modify a `tuple`. – Christian Tapia Jul 15 '15 at 19:18
1

Your function does not return anything, but it prints the result. If you just do :

def test():
    amounts = [1000, 2200, 800, 360]
    rate = 0.05
    addInterest(amounts, rate)

then test() will be None (which is the default return value of a function).

If you want your function to return a result, you have to change the print to a return like this :

def test():
    amounts = [1000, 2200, 800, 360]
    rate = 0.05
    addInterest(amounts, rate)
    return amount

Also, be careful when modifying a list in a function. See for example https://stackoverflow.com/a/17686659/4709400

Community
  • 1
  • 1
stellasia
  • 5,372
  • 4
  • 23
  • 43
1

Because lists are mutable and balances[i] = balances[i] * (1 + rate modified the values of amounts too, which was passed with the call addInterest(amounts, rate)

Thus addInterest() has an implicit return value in this case.

Geeocode
  • 5,705
  • 3
  • 20
  • 34
1

See this post about data model and in particular the part about mutability.

Here is an example of how lists are mutable

>>> arr = [1,2,3]
>>> arr[0] = 99
>>> print(arr)
[99, 2, 3]

When you call the addInterest function, passing the amounts array as a parameter, it modified that array. Here's another example showing how that occurs

def test(my_list):
    print(my_list)
    my_list[0] = 99
    print(my_list)

Now test in the interpreter

>>> arr = [1,2,3]
>>> x = test(arr)
[1,2,3] 
[99, 2, 3]
>>> arr
[99,2,3]
>>> x
>>> x is None
True

So you can see, the return value of the function is None, which we stored in the variable named x. But the function also has a side effect, which is to change the value of the list arr that was passed into it.

Finally, let's see an example like yours, where the array is defined inside a function.

def change_list(l):
    print(l)
    l[0] = 99
    print(l)


def test():
    arr = [1,2,3]
    change_list(arr)

and check it out in the interpreter

>>> x = test()
[1, 2, 3]
[99, 2, 3]
>>> x
>>> x is None
True

Hope this clears up any confusion.

krethika
  • 3,908
  • 1
  • 24
  • 27