Sal's Shipping Exercise - why use elif?

I’m a little confused by Sal’s Shipping Project.

To calculate the cheapest shipping option, I produced the code below.

As you can see, I use if … if …else for my control flow.

Using the sample weights provided, this prints two responses: the correct one, and then the premium shipping print message, which is incorrect.

If I use if…elif…else, then it produces just the correct answer. But I don’t understand why?

Any advice very welcome!

def cheapest_option(weight):
  if ground_shipping(weight) < premium_shipping and ground_shipping(weight) < drone_shipping(weight):
    print("Ground Shipping is the cheapest option. It will cost $" + str(ground_shipping(weight)))
  if drone_shipping(weight) < premium_shipping and drone_shipping(weight) < ground_shipping(weight):
    print("Drone Shipping is the cheapest option. It will cost $" + str(drone_shipping(weight)))
  else:
    print("Premium Shipping is the cheapest option. It will cost $" + str(premium_shipping))

After reading around, it seems that because the 1st if statement was deemed true, the subsequent else statement also printed because it was contrasting itself with the untested 2nd if statement. (I hadn’t realized that the 1st True if statement effectively ends the control flow).

I’m not positive that I’ve now solved my question, so any comments would be appreciated.

Aside

Rather than making multiple calls to the same functions, how about caching the results…

def cheapest_option(weight):
    ground = ground_shipping(weight)
    drone = drone_shipping(weight)

This lets us write a single conditional expression in the return statement…

  return ('Premium', premium) if premium < ground \
  and premium < drone else ('Ground', ground) if ground < drone \
  else ('Drone', drone)

Or, as you have above, to write simper conditionals in the if statement…

    if premium < ground and premium < drone:
        return ('Premium', premium)
    else if ground < drone:
        return ('Ground', ground)
    else:
        return ('Drone', drone)

The call will look like,

print ("{}: {:.2f}".format(cheapest_option(4.8)[0], cheapest_option(4.8)[1]))

Escaped newlines bother me, only place I’ll use them is in multiline strings:

'''\
blah blah
'''

For anything else, parenthesis are nicer:

  return (
      ('Premium', premium) if premium < ground and premium < drone
      else ('Ground', ground) if ground < drone
      else ('Drone', drone)
  )

Also, there’s a function for picking the smallest of something. min (with its key parameter) which allows listing all the options … and that’s it, no other logic.

    return min(
        [
            ('Premium', prem_ground_shipping),
            ('Ground', ground_shipping(weight)),
            ('Drone', drone_shipping(weight))
        ],
        key=itemgetter(1)
    )

(which also rules out some bugs. can’t have bugs where there’s no code.)

3 Likes

I have the exact same question, and I still don’t understand. Rather than suggesting a new way to solve the exercise (although that is appreciated), could anyone answer the original question? @samwestrop (and myself) are using the answer format provided in the solutions video, so this is why it would be helpful to understand why elif is necessary in this case, rather than just getting a whole different solution method. Thanks!

Consider,

Given A, B, and C, find the smallest (we won’t use values, they are theoretical)

if A < B and A < C:
    # go with A
elif C < A and C < B:
    # go with C
else:
    # go with B by default

Does this get closer to the sought after answer?

BTW, I only just now watched the video and completed the code the way Matt did, or nearly so.

Yes, that is the correct answer but I have trouble understanding exactly why if/if/else doesn’t work. I actually started my questions as a new thread here (Sal's Shipping - confused about elif/if) because I realized I actually somehow got a slightly different answer than samwestrop

One small twist in the logic that came out of this…

if A < B:
  # temp is A
else:
  # temp is B

if C < temp:
  # temp is C

That is still in keeping with the video, sort of. We’ve shed all the extra and needless logic, and on top of that, the elif.


This should not be confused with refactoring, but seen as a different planning strategy. Brick by brick. The fewer we need to make a plan work the better so exhaust simple models before devising more complex ones.


>>> def min_abc(a, b, c):
	return c < (a < b and a or b) and c or (a < b and a or b)

>>> min_abc(9,8,7)
7
>>> min_abc(9,8,17)
8
>>> min_abc(9,18,17)
9
>>> 

That’s just for shits and giggles.

Can’t stop there…

>>> def min_abc(a, b, c):
	def f(m, n):
		return m < n and m or n
	return c < f(a, b) and c or f(a, b)

>>> min_abc(9,8,7)
7
>>> min_abc(9,8,17)
8
>>> min_abc(9,18,17)
9
>>> 

Now refactored, slightly,

>>> def min_abc(a, b, c):
	d = a < b and a or b
	return c < d and c or d

>>> min_abc(9,8,7)
7
>>> min_abc(9,8,17)
8
>>> min_abc(9,18,17)
9
>>> 

I’m more confused. Below is my code and it works but was wondering if I should or when should I use elif when coding, so came here looking for answers? Also when does just using if statements and not incorporating elif into my code cause problems? Please use coding exercise to explain not A < B stuff. Please and Thank you

# program to calculate shipping costs
# Variables for program
premium_ground_shipping = 125.00
# Ground Shipping Pricing table
# 2lbs or less
price_1 = 1.50
# Over 2lbs but <= to 6lbs
price_2 = 3.00
# Over 6lbs but <= to 10lbs
price_3 = 4.00
# Over 10lbs
price_4 = 4.75

def cost_of_ground_shipping(weight):
  flat_charge = 20.00
  if weight <= 2.0:
    return (weight * price_1) + flat_charge
  if weight >= 2.0 and weight < 6.00:
    return (weight * price_2) + flat_charge
  if weight >= 6.0 and weight <= 10.00:
    return (weight * price_3) + flat_charge
  if weight > 10.0:
    return (weight * price_4) + flat_charge

def cost_of_drone_shipping(weight):
  if weight <= 2.0:
    return (weight * (price_1 * 3))
  if weight >= 2.0 and weight < 6.00:
    return (weight * (price_2 * 3))
  if weight >= 6.0 and weight <= 10.00:
    return (weight * (price_3 * 3))
  if weight > 10.0:
    return (weight * (price_4 * 3))

def cheapest_method(weight):
  ground = cost_of_ground_shipping(weight)
  drone = cost_of_drone_shipping(weight)
  if ground < drone and ground < 125:
    print("Ground shipping is cheapest at: $" + str(ground))
  elif drone < ground and drone < 125:
    print("Drone shipping is cheapest at: $" + str(drone))
  else:
    print("Premium ground shipping at flat rate of $125.00 is cheapest.")

cheapest_method(4.8)
...

Sorry, didn’t realize that “#” caused large bold type

When there are more than two possible outcomes, elif is necessary.

1 Like

Thanks, was thinking that but was trying to get clarification.

Re wrote it like this. Hopefully better for a newb.


# program to calculate shipping costs
# Variables for program
premium_ground_shipping = 125.00
# Ground Shipping Pricing table
# 2lbs or less
price_1 = 1.50
# Over 2lbs but <= to 6lbs
price_2 = 3.00
# Over 6lbs but <= to 10lbs
price_3 = 4.00
# Over 10lbs
price_4 = 4.75

def cost_of_ground_shipping(weight):
  flat_charge = 20.00
  if weight <= 2.0:
    return (weight * price_1) + flat_charge
  elif weight < 6.00:
    return (weight * price_2) + flat_charge
  elif weight <= 10.00:
    return (weight * price_3) + flat_charge
  else:
    return (weight * price_4) + flat_charge

def cost_of_drone_shipping(weight):
  if weight <= 2.0:
    return (weight * (price_1 * 3))
  elif weight < 6.00:
    return (weight * (price_2 * 3))
  elif weight <= 10.00:
    return (weight * (price_3 * 3))
  else:
    return (weight * (price_4 * 3))

def cheapest_method(weight):
  ground = cost_of_ground_shipping(weight)
  drone = cost_of_drone_shipping(weight)
  if ground < drone and ground < 125:
    print("Ground shipping is cheapest at: $" + str(ground))
  elif drone < ground and drone < 125:
    print("Drone shipping is cheapest at: $" + str(drone))
  else:
    print("Premium ground shipping at flat rate of $125.00 is cheapest.")

cheapest_method(4.8)
1 Like

Is the only difference between ground and drone shipping the flat charge?

Thanks, tried to do on first post but not working.

It works. Just try it on your next post.

Figured it out, thanks

1 Like