3

I wrote the function in python:

def is_number_like(x):
     try:
        int(x) + 1
    except:
        return False
    return True

is there any difference if I write float(x) or int(x)? Or could + 1 part be useful in some case?

EDIT: is_number_like will return True when string is passed - that is what I don't want to be. I would like a function which will return False anytime a text-like value is passed as an argument. Is there a method for this?

maybe:

def is_number_like(x):
     try:
        x + 1
    except:
        return False
    return True

will be better?

or maybe:

def is_number_like(x):
     try:
        float(x + 1) == float(x) + 1
    except:
        return False
    return True

I want to write a module which would accept any well-behaved number type which represents one dimensional real number (for example SimpleITK.sitkUInt8 number type or numpy.int32 and so on...).

I'm afraid that there could be libraries, which will not throw an error in casting to int or float. For example I can imagine situation like this:

>>> z = SomeComplexType(1. + 2.j)
>>> z
(1+2j)
>>> z -= 2.j
>>> z
(1+0j)
>>> float(z) # does not raise an error
1.

is this possible, should I worry about such situation?

And do all well designed real number types will cast to float without an error?

ps. i have read this already: How do I check if a string is a number (float)?

Śmigło
  • 937
  • 8
  • 14
  • 2
    Have you tried what `int("1.23")` does? What is `x` supposed to be anyway? A string, or some other number-like object? – tobias_k Jul 12 '17 at 16:06
  • 1
    I get an error for `float((1+0j))` w/ both python 2.7 and 3.5 ("TypeError: can't convert complex to float") – Scott Hunter Jul 12 '17 at 16:08
  • x should be a list, an array (i want to return False then) or a numpy.int (which i want to make my function return True) and so on – Śmigło Jul 12 '17 at 16:12

4 Answers4

2

There is a difference between float(..) and int(..).

float(..) will try to parse a string or any object that has a __float__ method. For example int, float and complex have a __float__ method. You can define such method for a custom class as well.

If you aim to convert a complex number to a float(..), it will error:

>>> float(2+2j)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float

The result of a float(..) function is guaranteed to be a float: if the __float__ method returns a non-float value, it will raise a TypeError:

>>> class Foo:
...     def __float__(self):
...         return 2j
... 
>>> float(Foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __float__ returned non-float (type complex)

So a simply float(..) try is sufficient:

def is_number_like(x):
     try:
        float(x)
        return True
    except TypeError, ValueError:
        return False

Most numeric-like types in Python (like the numpy.int16) **support such __float__ method.

int(..) on the other hand works with a string and with the __int__ method. Again if you call int(..), the result is guaranteed to be an int.

So in , you could use two checks: one for float(..) and one for int(..):

def is_number_like(x):
     try:
        int(x)
        return True
    except TypeError, ValueError:
        try:
            float(x)
            return True
        except TypeError, ValueError:
            return False

Or if you want to return the number-like object:

def is_number_like(x):
     try:
        return int(x)
    except TypeError:
        try:
            return float(x)
        except TypeError:
            return None

(this will return None if both attempts fail).

Mind that in , there is also a long type (and guess what, it works with __long__).

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    shouldn't you first try to cast to `int` and then `float`? Nothing will be `int` the way it is now. – Ma0 Jul 12 '17 at 16:14
  • @Ev.Kounis: I do not really get your comment. Can you please reformulate? – Willem Van Onsem Jul 12 '17 at 16:15
  • If you pass "1" in your `is_number_like()` function it will create a `float`, not an `int`. In my opinion, the outer `try` block should be like `int(x)` and if that fails try `float(x)`. For this example it does not make any difference because it only returns `True` \ `False` but generally speaking.. – Ma0 Jul 12 '17 at 16:16
  • @Ev.Kounis: no, it will return `True`. This is a *check* wether it *is* number-like, not converting it to a *number-like* object. But you are correct that if you want to convert it, you can try `int` first. Will alter the answer. – Willem Van Onsem Jul 12 '17 at 16:17
  • I noticed the return value later, sorry. But you get my point. – Ma0 Jul 12 '17 at 16:18
  • Also `float(1+0j)` raises a `TypeError` for me. What Python version are you running? – Ma0 Jul 12 '17 at 16:19
  • @Ev.Kounis: hmm. Somehow I tested this. But now I cannot reproduce this. Modified. Thanks for your remarks :). – Willem Van Onsem Jul 12 '17 at 16:23
2

If I understand correctly, what you're actually trying to do is find out whether an object behaves in "number"-like ways (e.g. can you append +1 to it). If so, there's an easier way:

>>> from numbers import Number
>>> 
>>> my_complex_number = 3-2j
>>> my_stringy_number = "3.14"
>>>
>>> isinstance(my_complex_number, Number)
True
>>> isinstance(my_stringy_number, Number)
False
Marc
  • 56
  • 3
1

In python complex numbers can't be directly converted to int nor float this would raise a TypeError: can't convert complex to....

Any other object than an "int or float convertible" one will raise a ValueError.

To make an object from a custom class "convertible" one will have to define the appropriate "dunders" __int__ and __float__, see doc

So a function that check if a object can be cast as a real number you can do this:

def is_real_number(number):
    try:
        int(number)
    except TypeError, ValueError:
        return False
    return True
lee-pai-long
  • 2,147
  • 17
  • 18
  • ok, that is clarifying - and what about string? is the other method i wrote better for excluding strings? (see edit in my post) – Śmigło Jul 12 '17 at 16:19
  • If the string only contains a number it will be cast otherwise it will also raise a ValueError – lee-pai-long Jul 12 '17 at 16:21
  • but i don't want it to cast any string to number. any advice how to make it universal working? – Śmigło Jul 12 '17 at 16:26
  • Check if the given object is an instance of string with the [isinstance](https://docs.python.org/3/library/functions.html#isinstance) builtin. (This will work also for string subclass) – lee-pai-long Jul 12 '17 at 16:30
  • Actually @Marc gave the best answer if you only want to check if the object is a number is the [numbers.Number](https://docs.python.org/3.6/library/numbers.html#numbers.Number) class – lee-pai-long Jul 12 '17 at 16:36
0

Why not just use

any([isinstance(x, t) for t in [float, int, complex]])

You can modify the list of types to be whatever you need it to be.

rd_nielsen
  • 2,407
  • 2
  • 11
  • 18