user16823527
user16823527

Reputation:

Python for loop won't check each string if it is empty

I'm learning Python and trying to build code where the for loop checks if a string is empty or non-numeric before it proceeds to add everything. How do I prevent it from going there and instead instruct it to loop through b to e?

Upvotes: 0

Views: 1334

Answers (3)

faemmi
faemmi

Reputation: 231

You should check your inputs and then compute the result. These are two separate concerns your code has to handle. Do not do these different operations simultaneously. In your case you try return the sum after having checked only the first element of chocolate. Of course this fails if your second element already is e.g. None.

You should also take care about your variable naming. In Python, everything you define outside the function is also known inside the function scope:

x = 1

def f(y):
    print(x)  # x is known here, will print 1
    print(y)  # will print 2

f(y=2)

Hence

chocolate = [...]

def f(chocolate):  # overwrites the `chocolate` variable defined previously
    print(chocolate)  # will print 1 instead of the list
    
f(chocolate=1)

Anyhow, to address your example, you should to something like the following:

A = input("Please input the price of the first chocolate:")
...
E = input("Please input the price of the 5th chocolate:")

CHOCOLATE = [A, B, C, D, E]
# naming convention: global variables, i.e. such declared outside a function/class scope
# should be capitalized

def chocolatebill(chocolates):
    _validate_input(chocolates)
    bill_day = sum(map(int, chocolates))
    bill_week = 5 * bill_day
    return f"Your bill for today is {bill_day}. The total bill for this week is {bill_week}."

def _validate_input(chocolates):
    if len(chocolates) != len(set(chocolates)):  
        # this does not need to be checked every time in the for loop
        raise Exception("Double check your input. The price of each chocolate must be different.") 
    for i in chocolates:
        if not i:  # checks if the input is an empty string (evaluates to True if empty)
            raise Exception("You missed a price. Go back and input each price again.")
        elif not i.isnumeric():  # instead of `... == False`
            raise Exception("You missed a price. Go back and input each price again.")         
        
print(chocolatebill(CHOCOLATE))

A few points here:

  • No input via the input method always results in an empty string (''), never in None
  • Instead of returning stuff in the validation, raise an Exception. Ideally you even want dedicated exceptions, e.g. InvalidPriceError like
    class InvalidPriceError(Exception):
        pass
    
    raise InvalidPriceError("You missed a price. Go back and input each price again.")
    
    This makes your code much more expressive.
  • sum(map(int, chocolates)) is valid for an arbitrary number of chocolate prices. Here sum returns the sum of elements in a a list-like element. map(int, chocolates) here maps the int method onto the chocolates list, i.e. trys to apply it to each element and returns a list of the result (i.e. a generator to be precise).
  • I used an underscore before the _validate_input function because it is supposed to be a "private" method. I.e. it is supposed to be only used inside the scope of the chocolatebill function. This is a Python naming. convention.

There is even a lot more to mention here, but I don't want to stress you with too much information. I think this is already enough.

Upvotes: 0

abdullaev
abdullaev

Reputation: 11

if i == None: - this condition will not work if variable == ''

I replaced it with if not all(tuple(map(bool, chocolate))) - it is going to make all empty elements in list bool type. If element is empty it will be False else True. all() function checks if all the elements in list are True - it will return True.

Also i replaced this elif i.isnumeric() == False:, with this not all(tuple(map(str.isdigit, chocolate))), this code will use for each element method isdigit, works like previous one.

So then i think this elif len(chocolate) != len(set(chocolate)): part of your code is quite ok

Instead of this long code billday = int(a) + int(b) + int(c) + int(d) + int(e), you can use sum() function: billday = int(a) + int(b) + int(c) + int(d) + int(e)

And the last one i replaced code in else with f string: f"Your bill for today is {billday}. The total bill for this week is, {5 * billday}."

This is the final code:

b = input("Please input the price of the 2nd chocolate:")
c = input("Please input the price of the 3rd chocolate:")
d = input("Please input the price of the 4th chocolate:")
e = input("Please input the price of the 5th chocolate:")

chocolate = [a, b, c, d, e]


def chocolatebill(chocolate):
    if not all(tuple(map(bool, chocolate))) or not all(tuple(map(str.isdigit, chocolate))):
        return "You missed a price. Go back and input each price again."
    elif len(chocolate) != len(set(chocolate)):
        return "Double check your input. The price of each chocolate must be different."
    else:
        billday = sum(map(int, chocolate))
        return f"Your bill for today is {billday}. The total bill for this week is, {5 * billday}." 
    
print(chocolatebill(chocolate))```

Upvotes: 1

Óscar López
Óscar López

Reputation: 236114

There are several mistakes in your code:

  • Have you realized that a, b, c, d, e do not exist inside your function? you're working with a list now, not with the individual variables that only exist outside your function! Accumulate the result of the sum in a variable instead, and print it outside the loop.
  • To compare a value against None use is, not ==.
  • The validation for checking if there are duplicates should be done outside the loop.
  • You must not return on each condition! wait until the loop is over before returning.

Upvotes: 1

Related Questions