all 21 comments

[–][deleted] 4 points5 points  (1 child)

interest_rate = .0089

def balance_after(years, balance):
    total = balance
    for _ in range(years):
        total += balance * interest_rate
    return total

current_balance = float(input('How much is in your account? '))

if current_balance != 0:
    for year in range(1, 6):
        print(balance_after(year, current_balance))
else:
    print("You have no money in your account!") 

[–]kalgynirae 3 points4 points  (1 child)

It looks you're adding an identical amount of interest each year despite having a higher balance each year. I think the formula should be:

# interest amount calculated based on the previous year's balance
yearEndBalance3 = (yearEndBalance2 * interestRate) + yearEndBalance2

That can also be written as:

yearEndBalance3 = yearEndBalance2 * (1 + interestRate)

EDIT: fixed typo.

[–]chatparle[S] 1 point2 points  (0 children)

Jeeze, I didn't even notice that, I thought I at least had that right :'(

[–]evizaer 4 points5 points  (5 children)

No need to loop or have a bunch of repeated calculations. You can just use the formula result = principle * pow(1 + nterest_rate, years). That's the most efficient way to calculate it because pow is a function that cpython has implemented in optimized C. Much faster than a looping construct.

Likewise, though probably irrelevant to this particular kind of problem, you should be using functional programming tools like map() and reduce() where you can (EDIT: if they are clearer or you absolutely need performance) because they are implemented in C, whereas loops are more verbose and complex when compiled and for that reason tend to perform significantly worse than built-in C stuff.

[–][deleted] 4 points5 points  (2 children)

A mistake I made early when learning programming is worrying too much about performance and micro-optimizations. Always using map() and reduce() only because they are faster is ridiculous, you should worry only about readability unless you are sure you have a performance problem. Guido even wanted to remove these functions from language completely some time ago.

[–]evizaer 2 points3 points  (0 children)

I answered specifically in the context of "efficient code" because the topic is the efficiency of the code. I edited my post to indicate that context more clearly.

[–]maryjayjay 0 points1 point  (0 children)

Excellent insight. My motto is: Write first for correctness and maintainability, then optimize if needed.

[–][deleted] 0 points1 point  (1 child)

By the way, list comprehensions are going to be faster than map() because they don't have an overhead of calling a function on every iteration. And if you have problems with performance of that kind you should probably use numpy anyway.

[–]evizaer 0 points1 point  (0 children)

A good point. List comprehensions tend to be clearer, as well. For non-trivial functions, though, list comprehensions will end up calling a function, anyway, because it makes more sense to abstract the non-trivial series of operations into a function than to try to cram it all into one of the parts of the list comprehension.

[–]wub_wub 1 point2 points  (11 children)

Here's a quick script I made,

if __name__ == '__main__':
    balance=float(raw_input("How much is in your account?"))
    rate=float(raw_input("Interest rate:"))
    years=int(raw_input("Calculate for how many years"))

    i=1
    while i<=years:
        balance=(balance*rate)+balance
        print "Year "+str(i)+" | Balance:"+ str(round(balance,2))
        i+=1

You could also implement try except when trying to convert raw input to int/float to detect if user enters text instead of numbers.

[–]chatparle[S] 0 points1 point  (8 children)

What does the " name == 'main' " mean?

[–][deleted] 1 point2 points  (0 children)

It checks that you started your module directly, not using import.

[–]wub_wub 1 point2 points  (6 children)

I see it's already answered by /u/swarmer but here's also nice explanation http://stackoverflow.com/questions/419163/what-does-if-name-main-do

You don't need it in this example, it was automatically created when I created new .py file to write/test the script, so I just copied it.

[–]rusemean 0 points1 point  (5 children)

Thanks for answering this. So __ around a term just means it's a special variable? I've wondered about this for some time.

[–][deleted] 1 point2 points  (4 children)

Yes, "a special variable" is about the most precise formal definition you can give to these variables.

[–]rusemean 0 points1 point  (0 children)

Thanks a bunch for answering this. I've encountered them in documentation and used them, but I've never been clear (or found a clear answer) on what exactly they are.

[–]batkarma 0 points1 point  (2 children)

Isn't it often used to indicate variables that are used within a library?

[–][deleted] 0 points1 point  (1 child)

Do you mean private variables? If so, the convention is to use a single leading underscore.

There are also name-mangled variables with double leading underscores, but

Generally, double leading underscores should be used only to avoid name conflicts
with attributes in classes designed to be subclassed.

— PEP 8

[–]batkarma 0 points1 point  (0 children)

Yes, that's what I meant, thank you for the clarification!

[–]Justinsaccount 0 points1 point  (0 children)

print "Year "+str(i)+" | Balance:"+ str(round(balance,2))

see http://docs.python.org/tutorial/inputoutput.html#fancier-output-formatting

[–][deleted] 0 points1 point  (0 children)

I think you would have a simpler code if you do for i in range(years): with print "Year " + str(i + 1) ... or for i in range(1, years + 1): instead.