LuCS
LuCS

Reputation: 47

How could I best work around the function comparison TypeError in this case?

I'm trying to make program which automatically determines the cheapest method of mailing a package based on its weight.

The code is refusing to run however as I keep getting the following TypeError: '<' not supported between instances of 'function' and 'function'.

I tried turning the functions into floats with: if float(cost_ground) < float(cost_drone) and float(cost_ground) < float(cost_premium): But this returns the following TypeError: float() argument must be a string or a number, not 'function'.

Any advice and/or explanation on how to solve this?

Here is the full code:

def cheapest(weight):
  def cost_ground(weight):
    if weight <= 2:
      return float((weight * 1.50) + 20)
    elif weight <= 6:
      return float((weight * 3.00) + 20)
    elif weight <= 10:
      return float((weight * 4.00) + 20)
    else:
      return float((weight * 4.75) + 20)
  def cost_drone(weight): 
    if weight <= 2:
      return float((weight * 4.50))
    elif weight <= 6:
      return float((weight * 9.00)) 
    elif weight <= 10:
      return float((weight * 12.00))
    else:
      return float((weight * 14.25))
  def cost_premium(weight):
    return 125.00  
  if cost_ground < cost_drone and cost_ground < cost_premium:
   return "Ground shipping is the cheapest at $" + cost_ground
  if cost_drone < cost_ground and cost_drone < cost_premium:
    return "Drone shipping is the cheapest at $" + cost_drone
  if cost_premium < cost_ground and cost_premium < cost_drone:
    return "Premium ground shipping is the cheapest at $" + cost_premium

Upvotes: 2

Views: 57

Answers (4)

GaryMBloom
GaryMBloom

Reputation: 5690

You are comparing the actual Python function objects rather than the results returned by those functions. In Python, a function name can be treated like a variable if the function is not invoked. You've already got the weight argument passed to the top-level function cheapest(), so pass it to functions. So your code:

  if cost_ground < cost_drone and cost_ground < cost_premium:
     return "Ground shipping is the cheapest at $" + cost_ground

becomes:

  if cost_ground(weight) < cost_drone(weight) and cost_ground(weight) < cost_premium(weight):
      return "Ground shipping is the cheapest at $" + cost_ground

Also note that comparisons like these can be ganged together. So a simpler way of writing the if line of the code would be:

   if cost_drone(weight) > cost_ground(weight) < cost_premium(weight):

Upvotes: 0

Faisal Afzal
Faisal Afzal

Reputation: 273

Every function when called needs to be given it's parameters. The only situation where a function can be called without any parameters is if the function itself takes no parameters. The following code should make that clear:

def function_a():
    print("No parameters required.")

def function_b(parameter_1,parameter_2):
    return parameter_1 + parameter_2
function_a()
function_b()

Calling the first function without any parameters will not produce any errors however calling the second function will produce an error since it takes two parameters and it has been given none.

In your code, you are not passing a parameter to the functions. Defined by your ownself, cost_ground() takes a weigth parameter. When you are calling that function, you are calling it without the parameter. Hence it should be:

if float(cost_ground(weight)) < float(cost_drone(weight)) and float(cost_ground(weight)) < float(cost_premium(weight)):

In addition to this when you return the values, you must convert values from float to string as follows:

return "Ground shipping is the cheapest at $" + str(cost_ground(weight))

Otherwise it will given the following error:

TypeError: can only concatenate str (not "float") to str

Full code is given below, it should work fine now.

def cheapest(weight):
  def cost_ground(weight):
    if weight <= 2:
      return float((weight * 1.50) + 20)
    elif weight <= 6:
      return float((weight * 3.00) + 20)
    elif weight <= 10:
      return float((weight * 4.00) + 20)
    else:
      return float((weight * 4.75) + 20)
  def cost_drone(weight):
    if weight <= 2:
      return float((weight * 4.50))
    elif weight <= 6:
      return float((weight * 9.00))
    elif weight <= 10:
      return float((weight * 12.00))
    else:
      return float((weight * 14.25))
  def cost_premium(weight):
    return 125.00
  if float(cost_ground(weight)) < float(cost_drone(weight)) and float(cost_ground(weight)) < float(cost_premium(weight)):
   return "Ground shipping is the cheapest at $" + str(cost_ground(weight))
  if cost_drone < cost_ground and cost_drone < cost_premium:
    return "Drone shipping is the cheapest at $" + str(cost_drone(weight))
  if cost_premium < cost_ground and cost_premium < cost_drone:
    return "Premium ground shipping is the cheapest at $" + str(cost_premium(weight))
 

Upvotes: 0

mhawke
mhawke

Reputation: 87124

cost_ground, cost_drone and cost_premium are all functions. There is no concept of one function being greater than another. For example:

>>> def f1(): return 1
>>> def f2(): return 2
>>> f1 > f2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'function' and 'function'

You meant to call the functions and to do that you need to use parentheses and optionally arguments as defined by the functions. Using the above functions:

>>> f1() > f2()
False

This works because it is the return values of the functions that is being compared, not the function objects.

For example, cost_ground is defined as accepting an argument named weight so that needs to be supplied when calling the function; cost_ground(5) will return a float value 35.0.

So you should be doing this:

weight = 5
if cost_ground(weight) < cost_drone(weight) and cost_ground(weight) < cost_premium(weight):
    return f"Ground shipping is the cheapest at ${cost_ground(weight)}"

Upvotes: 2

Marksverdhei
Marksverdhei

Reputation: 31

cost_premium and cost_ground are functions and not numbers. They should be called in such a way that they evaluate to numbers:

instead of ìf cost_premium < cost_ground ... do if cost_premium(weight) < cost_ground(weight) ...

Upvotes: 0

Related Questions