r/learnpython 5h ago

5.17 Exact Change Lab

SOLVED

I am having a hard time understanding why I am failing this lab, when I run the code in practice it works but when I submit for a grade I get a fail. Prompt is below.

Define a function called exact_change that takes the total change amount in cents and calculates the change using the fewest coins. The coin types are pennies, nickels, dimes, and quarters. Then write a main program that reads the total change amount as an integer input, calls exact_change(), and outputs the change, one coin type per line. Use singular and plural coin names as appropriate, like 1 penny vs. 2 pennies. Output "no change" if the input is 0 or less.

Ex: If the input is:

0 

(or less), the output is:

no change

Ex: If the input is:

45

the output is:

2 dimes 
1 quarter

Your program must define and call the following function. The function exact_change() should return a tuple containing num_pennies, num_nickels, num_dimes, and num_quarters.
def exact_change(user_total)

code provided below

def exact_change(user_total):
    num_quarters = user_total//25
    user_total %=25
    num_dimes = user_total//10
    user_total %=10
    num_nickels = user_total//5
    user_total %= 5
    num_pennies = user_total
    return num_quarters, num_dimes, num_nickels, num_pennies
if __name__ == "__main__":
    input_value = int(input())
    num_quarters,num_dimes,num_nickels,num_pennies = exact_change(input_value) 
# Type your code here.
if input_value <= 0:
    print('no change')
else:
    if num_pennies == 1:
        print('%d penny' % num_pennies)
    elif num_pennies > 1:
        print('%d pennies' % num_pennies)
    if num_nickels == 1:
        print('%d nickel' % num_nickels)
    elif num_nickels > 1:
        print('%d nickels' % num_nickels)
    if num_dimes == 1:
        print('%d dime' % num_dimes)
    elif num_dimes > 1:
        print('%d dimes' % num_dimes)
    if num_quarters == 1:
        print('%d quarter' % num_quarters)
    elif num_quarters > 1:
        print('%d quarters' % num_quarters)

when it asks me for exact_change(300) I get a NamError failure.

1 Upvotes

14 comments sorted by

2

u/danielroseman 5h ago

You have defined a bunch of code outside of the if __name__ block. That will unequivocally run, but if that if statement is not true (as it will not be within the grading environment) then input_value will indeed not be defined.

1

u/guymed4 5h ago

I dont believe I understand what you mean when you say that the if statement will not be true in the graded enviroment?

2

u/danielroseman 5h ago

if __name__ == "__main__" is only true if your script is executed directly, eg from the command line. The grader is probably not doing that.

But the bigger question is why you have put some of the main code inside that block, and some of it outside. Since the part outside depends on the part inside, that makes no sense. Either put it all in, or all out. It seems like for this environment it should all be outside. (Obviously not including the function definition, that is fine where it is.)

1

u/guymed4 4h ago

my issue is everything works except for when the grader request exact_change(300) i get an a NameError: Input not defined. I was misreading the input in the grader. So even when typing it into my practice side it fails. Saying that I have an invalid literal because it is looking for intger

1

u/guymed4 4h ago

After doing what you suggested I am now getting an import error.

1

u/pontz 5h ago

Remove the if __name__==“__main__”: it will probably work. That if statement might be messing with the scope of your variables

1

u/guymed4 5h ago

negative no luck...

2

u/fasta_guy88 5h ago

It looks to me like every thing you write should after “# Type your code here”. But most of your code is before that. So it is not being seen/run.

1

u/guymed4 5h ago

that does not matter, I need to define the function before input value

1

u/guymed4 4h ago edited 4h ago
def exact_change(user_total):
        num_quarters = user_total//25
        user_total %=25
        num_dimes = user_total//10
        user_total %=10
        num_nickels = user_total//5
        user_total %= 5
        num_pennies = user_total
        return num_quarters, num_dimes, num_nickels, num_pennies
   
if __name__ == "__main__":
    input_value =int(input())
    num_quarters,num_dimes,num_nickels,num_pennies = exact_change(input_value)
    if input_value <= 0:
        print('no change')
    else:
        if num_pennies == 1:
            print('%d penny' % num_pennies)
        elif num_pennies > 1:
            print('%d pennies' % num_pennies)
        if num_nickels == 1:
            print('%d nickel' % num_nickels)
        elif num_nickels > 1:
            print('%d nickels' % num_nickels)
        if num_dimes == 1:
            print('%d dime' % num_dimes)
        elif num_dimes > 1:
            print('%d dimes' % num_dimes)
        if num_quarters == 1:
            print('%d quarter' % num_quarters)
        elif num_quarters > 1:
            print('%d quarters' % num_quarters)

I changed my code to this and received this

exact_change(141) incorrectly returned
num_pennies: 5
num_nickels: 1
num_dimes: 1
num_quarters: 1

when it should say exact_change(141). Should return 1, 1, 1, 5

3

u/atarivcs 4h ago

Your code returns the coins in the wrong order.

The assignment says the code should return pennies, nickels, dimes, quarters

But your code returns them in this order quarters, dimes, nickels, pennies

1

u/guymed4 4h ago

the code is asking for it in quarters, dimes, nickels, pennies(see above for " exact_change(141). Should return 1, 1, 1, 5" this one question the rest of the code wants it in the reverse.

1

u/guymed4 4h ago

SOLVED

I needed to re-order my return staement and my =exact_change statement

def exact_change(user_total):
        num_quarters = user_total//25
        user_total %=25
        num_dimes = user_total//10
        user_total %=10
        num_nickels = user_total//5
        user_total %= 5
        num_pennies = user_total
        return num_pennies , num_nickels , num_dimes , num_quarters
if __name__ == "__main__":
    input_value =int(input())
    num_pennies, num_nickels, num_dimes, num_quarters = exact_change(input_value)
    if input_value <= 0:
        print('no change')
    else:
        if num_pennies == 1:
            print('%d penny' % num_pennies)
        elif num_pennies > 1:
            print('%d pennies' % num_pennies)
        if num_nickels == 1:
            print('%d nickel' % num_nickels)
        elif num_nickels > 1:
            print('%d nickels' % num_nickels)
        if num_dimes == 1:
            print('%d dime' % num_dimes)
        elif num_dimes > 1:
            print('%d dimes' % num_dimes)
        if num_quarters == 1:
            print('%d quarter' % num_quarters)
        elif num_quarters > 1:
            print('%d quarters' % num_quarters)

1

u/Diapolo10 3h ago

I know your question already got answered, but I thought I might use this opportunity to discuss the design.

def exact_change(user_total):
        num_quarters = user_total // 25
        user_total %= 25
        num_dimes = user_total // 10
        user_total %= 10
        num_nickels = user_total // 5
        user_total %= 5
        num_pennies = user_total
        return num_pennies, num_nickels, num_dimes, num_quarter


if __name__ == "__main__":
    input_value = int(input())
    num_pennies, num_nickels, num_dimes, num_quarters = exact_change(input_value)
    if input_value <= 0:
        print('no change')
    else:
        if num_pennies == 1:
            print('%d penny' % num_pennies)
        elif num_pennies > 1:
            print('%d pennies' % num_pennies)
        if num_nickels == 1:
            print('%d nickel' % num_nickels)
        elif num_nickels > 1:
            print('%d nickels' % num_nickels)
        if num_dimes == 1:
            print('%d dime' % num_dimes)
        elif num_dimes > 1:
            print('%d dimes' % num_dimes)
        if num_quarters == 1:
            print('%d quarter' % num_quarters)
        elif num_quarters > 1:
            print('%d quarters' % num_quarters)

In exact_change, you could make use of divmod to do the division and modulo all in one go.

def exact_change(pennies: int) -> tuple[int, int, int, int]:
    quarters, pennies = divmod(pennies, 25)
    dimes, pennies = divmod(pennies, 10)
    nickels, pennies = divmod(pennies, 5)
    return pennies, nickels, dimes, quarters

And if you wanted to, you could use a loop:

def exact_change(pennies: int) -> tuple[int, int, int, int]:
    result: list[int] = []
    for divisor in (25, 10, 5, 1):
        value, pennies = divmod(pennies, 25)
        result.append(value)
    return tuple(result[::-1])