-4

Why won't this work???

def distance_from_zero(x):        
    if type(x) == int or float:
        return abs(x) 
    else:
        return "Not an integer or float!"

print distance_from_zero(2050)

However this is the correct answer which is the same thing!

def distance_from_zero(x):    

    if type(x) == int or type(x) == float:
        return abs(x) 
    else:
        return "Not an integer or float!"

print distance_from_zero(2050)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Mr.Bill
  • 179
  • 14

1 Answers1

8

These are not the same thing. Compare these two lines:

if type(x) == int or float:

if type(x) == int or type(x) == float:

And that's the difference.

The first one is checking type(x) == int, and then taking the result and oring it with float, so it's going to return True if x is an int, and float if it's anything else. Since both True and float are truthy values, the if part will always happen, and the else will never happen.

The second one is checking type(x) == int, and type(x) == float, and oring them together. So, it's going to return True if x is an int or if x is a float, and False if it's anything else.

You can simplify the code by using the in operator:

if type(x) in (int, float)

But it's still not very good Python. If you really want to type-switch, you almost always want to do it with isinstance rather than comparing the types:

if isinstance(x, (int, float)):

This means your code will work if it's passed, say, a subclass of int. But it still won't work for, say, a wrapper around int, or some custom-designed integral type, or even (in Python 2.x) a long. So, a better version is:

if isinstance(x, numbers.Real)

This returns True for float, int, long, and various other builtin types, and any subclasses of those types, and anything that registers itself with the numbers.Real ABC.

But really, you usually don't want to type-switch at all. Python is designed around duck typing. What you care about here is that you can successfully pass it to abs. Who cares what specific type it actually is, as long as you can do that? So:

try:
    return abs(x)
except TypeError:
    return "Not a number!"

Or, even better, instead of catching the exception and returning a string (which means that any caller is going to have to handle both numbers and strings, and so on up the chain), just let the exception propagate:

return abs(x)
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • indeed. The first is always true! – kindall Apr 11 '13 at 21:41
  • In many languages the `or float` would be a syntax error. It's unfortunate that it's valid in Python, as lots of people seem to make this mistake. – Mark Ransom Apr 11 '13 at 21:42
  • @MarkRansom: In what languages would it be a syntax error? (OK, obviously languages where types aren't first-class values, but you can get the same problem with `x == 1 or 2` in those languages.) – abarnert Apr 11 '13 at 21:47
  • ahh okay. It drove me crazy as to why it wouldn't work. I'm recently starting to learn programming/python so i'm not much experienced with it. – Mr.Bill Apr 11 '13 at 21:50
  • @MarkRansom: A warning for "expression where people get the precedence wrong more often than they get it right" and/or for "logical operator used with literal operand" might be useful. (For example, clang gives you multiple warnings for `x == 1 || 2`, and gives suggestions like "if you want a bitwise operation, use '|'".) – abarnert Apr 11 '13 at 21:54
  • @mrdjhiphop23: No problem. Next time you run into something like this, break it down into the smallest pieces possible and print out every intermediate result. For example, `type_is_good = type(x) == int or float; print(type_is_good)` would show you that it's printing out `True` for integers (good), `float` instead of `True` for floats (worrying), and `float` instead of `False` for strings (definitely wrong). – abarnert Apr 11 '13 at 21:57
  • @abarnert, you're right I wasn't considering all the possibilities, just that `float` as a type wouldn't work. Maybe because Python uses `or` instead of some funny symbol it makes people think it should work the same as it does in English? – Mark Ransom Apr 11 '13 at 22:06
  • @MarkRansom: Good point. In fact, in general, being more like plain English (or at least "executable pseudocode") may make encourage bad assumptions sometimes. (The huge benefits for everyone ranging from one step beyond absolute beginning up to experts probably more than make up for that, but maybe it's still something to take into account when writing tutorials or class syllabi or whatever.) – abarnert Apr 11 '13 at 23:03