0

I don't understand why the following does not operate correctly and raises errors when radius or height are float numbers.

def cone(radius, height):
    if isinstance(radius, int) or isinstance(radius,float) == False:
        raise TypeError("Error: parameters radius and height must be numeric.")
    if isinstance(height, int) or isinstance (height,float)== False:
        raise TypeError("Error: parameters radius and height must be numeric.")

    if radius > 0 and height > 0:
            return ((radius*radius)*(3.1415)*(height/3))
    if radius<=0:
        raise ValueError("Error: radius must be positive.")
    if height <=0:
        raise ValueError("Error: height must be positive.")
Elle
  • 75
  • 1
  • 6

3 Answers3

2

Seems like you want

if not (isinstance(radius, int) or isinstance(radius,float)):

Or actually

if not isinstance(radius, (float, int)):

Currently your logic is this

if isinstance(radius, int) or (isinstance(radius,float) == False):

So, if you got an int, then you get the error. If you get a float, you get no error because you end up with False or (True == False)

Anything or False is the same as bool(Anything), which in this case, True == False, which is False

Also, I suggest raising all errors and checking conditions first.

Then just return the actual math because there's no way the variables couldn't be positive at that point

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
2

You can pass multiple types to isinstance, so you can get rid of or:

def cone(radius, height):
    if not isinstance(radius, (float, int)):
        raise TypeError("Error: parameters radius and height must be numeric.")
    if not isinstance(height, (float, int)):
        raise TypeError("Error: parameters radius and height must be numeric.")

    if radius > 0 and height > 0:
            return ((radius*radius)*(3.1415)*(height/3))
    if radius<=0:
        raise ValueError("Error: radius must be positive.")
    if height <=0:
        raise ValueError("Error: height must be positive.")

for value in [(1, 2), (0.33, 'foo')]:
    print(cone(*value))

Output:

0.0
Traceback (most recent call last):
  File "/private/tmp/s.py", line 15, in <module>
    print(cone(*value))
  File "/private/tmp/s.py", line 5, in cone
    raise TypeError("Error: parameters radius and height must be numeric.")
TypeError: Error: parameters radius and height must be numeric.
Maurice Meyer
  • 17,279
  • 4
  • 30
  • 47
1

Your problem is that the if is evaluated as:

if (isinstance(radius, int)) or (isinstance(radius,float) == False)

and I guess this is not what you meant.

Anyway, you can actually make your code simpler by using try/except. You can just assume your arguments are numbers and do the comparison to 0. If they are not, an exception will be raised so you can catch it:

def cone(radius, height):
    try:
        if radius > 0 and height > 0:
            return ((radius*radius)*(3.1415)*(height/3))
        else:
            raise ValueError("Error: radius and height must be positive.")

    except TypeError:
        raise TypeError("Error: parameters radius and height must be numeric.")
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • Depends on the objects being passed and if they implement `__gt__`... Checking types would be safe, or using type hints would be better – OneCricketeer Jun 10 '20 at 16:10