String method to check for a float

It would be nice to have a string method that checks for a float. Currently there is no support for this, either built-in or in the standard library. There is a thread, dating back to Dec 2020, that proposes a trivial implementation for str.isfloat . I was thinking of a method that did more. Consider the following code. It returns True if the string is a proper float, False if it is an int and None otherwise. def isfloat(s): try: int(s) return False except ValueError: try: float(s) return True except ValueError: return None This will be useful when we want to preserve the type of the number that is in string format. Anywhere a number is input as a string to a method and we want to later on output the original number, we can use the above. If, instead (as suggested in the other thread), the string is simply converted to a float, then the info that the string was an int is lost.

I don't know how common it is to want to distinguish between string representations of integers and those of floats. It seems like a function that could have a million little variations: What if my boss says that now my input integers can have commas? Or have extra space added? Or if integer-valued floats should be considered integers? What if we run into localization issues with a commas-versus-periods-as-decimal-separator? What if we want to start accepting fractions like "22/7"? What if we find dollar signs in front? What if we want to return 0 or NaN in place of None? It seems to me that with all of these possible variations, it's best to spell out in your code exactly what to do for your individual use case, using try/except as necessary. That's not to say that you shouldn't make this function in your own code -- maybe you're personally writing dozens of scripts that use exactly this function. If so, great: add it to a personal utility library and import it when you need it. But I'm not sure it's worth the bloat of giving that same function to all Python users across the world whether they want it or not. By the way, if I were implementing something like this, I would probably instead write something like def parse_value(string): try: return int(string) except ValueError: pass try: return float(string) except ValueError: return None so that all of the parsing is together, and then elsewhere in the code write isinstance(number, float) rather than passing strings around and repeatedly parsing/re-parsing with some kind of isfloat(string) operation.

The method need not take care of every variation. Currently there is no method to check for a float in a string even without formatting. str.numeric or str.decimal don't work. str.isfloat would test unformatted strings for floats or ints just like the functions int() and float() convert strings of numbers. As for the use cases, I can think of 2: 1. When accepting user input with the input() function, you may get integers and not floats. If you just convert the strings to floats, you will get the result of a calculation as a float. Here the type of the input needs to be preserved. 2. A case that may come up often is passing numbers as strings to an instance method. After converting the number to a float, you may want to output the value in a repr method. Saving the precise type would help. The parse_value function would work as well but str.isfloat is more inline with the current string methods. Also string methods return either a boolean or a string and parse_value returns a number and is suited to a personal library. Why do you call it 'bloat'? It is just one function with a few lines of code. Other languages like Haskell have much bigger libraries.

On Sat, Oct 2, 2021 at 12:19 PM Debashish Palit <dpalit17@outlook.com> wrote:
Because your version of the function is slightly different from other people's versions. Making it part of the core language would require that it be right for everyone. Instead, just have the simple version in your own code, and it can be perfect for your usage. ChrisA

Having such a method in the core helps avoid writing the function repeatedly. (This would especially help beginners.) My version is suited to the core language as a string method. parse_value as given by Dennis Sweeney is suited to user code.

On Sat, Oct 02, 2021 at 02:17:32AM -0000, Debashish Palit wrote:
The method need not take care of every variation. Currently there is no method to check for a float in a string even without formatting.
Right, because no method is needed. If you want to convert something to a float (whether a string, or anything else), it is nearly always better to try to convert it: try: result = float(s) except TypeError: # Cannot be converted to a float. ... # some fallback routine This software pattern is called "Easier to Ask Forgiveness than Permission" and is usually more efficient and safer than the opposite pattern, "Look Before You Leap". https://devblogs.microsoft.com/python/idiomatic-python-eafp-versus-lbyl/ So the number of use-cases for your function are probably very few.
Can you give a real example of a case where you are doing calculations on a number provided as a string, but need to preserve the original format?
2. A case that may come up often is passing numbers as strings to an instance method.
Why pass your numbers to functions as *strings* if you want to do calculations with them?
If you need to preserve the exact input for the repr method, you should preserve the actual input. class MyClass: def __init__(self, astring): self._arg = astring self.number = float(astring) def __repr__(self): return 'MyClass(%s)' % self._arg
The parse_value function would work as well but str.isfloat is more inline with the current string methods.
Not really. There are no string methods to test for: - ints - floats - complex numbers - fractions - decimals you are expected to just try to convert and catch the exception if it occurs (EAFP). So this would be new. The existing string methods isdecimal, isdigit and isnumeric test for Unicode categories, for example: '\N{CIRCLED DIGIT THREE}'.isdigit() --> returns True '\N{CIRCLED DIGIT THREE}'.isdecimal() --> returns False '\N{ETHIOPIC NUMBER FIFTY}'.isnumeric() --> returns True '\N{ETHIOPIC NUMBER FIFTY}'.isdigit() --> returns False -- Steve

Steven D'Aprano wrote: > On Sat, Oct 02, 2021 at 02:17:32AM -0000, Debashish Palit wrote: > > The method need not take care of every variation. Currently there is > > no method to check for a float in a string even without formatting. > > Right, because no method is needed. If you want to convert something to > a float (whether a string, or anything else), it is nearly always > better to try to convert it: > try: > result = float(s) > except TypeError: > # Cannot be converted to a float. > ... # some fallback routine > This software pattern is called "Easier to Ask Forgiveness than > Permission" and is usually more efficient and safer than the opposite > pattern, "Look Before You Leap". > https://devblogs.microsoft.com/python/idiomatic-python-eafp-versus-lbyl/ > So the number of use-cases for your function are probably very few. I am not against EAFP. It should be used, but when you have decide between an int and a float, you would need to apply it twice. str.float is a convenience method wrapping that. > > > > When accepting user input with the input() function, you may get > > > > integers and not floats. If you just convert the strings to floats, > > you will get the result of a calculation as a float. Here the type of > > the input needs to be preserved. > > Can you give a real example of a case where you are doing calculations > on a number provided as a string, but need to preserve the original > format? Real example =========== Consider a number radix conversion software. It needs to accept the input number as a string (say '15A' in base 12). When we provide it a base 10 number, it would also be a string. If we are storing the base 10 equivalent of the input number, then we need to convert the input number to the correct type - float or int. Otherwise calculations may not be accurate - addition may yield a float when an int was expected. > > After converting the number to a float, you may want > > to output the value in a repr method. Saving the precise type would > > help. > > If you need to preserve the exact input for the repr method, you should > preserve the actual input. > class MyClass: > def __init__(self, astring): > self._arg = astring > self.number = float(astring) > def __repr__(self): > return 'MyClass(%s)' % self._arg Here you are storing the same info twice - as a string and as a number. Why not just store a number? > > The parse_value function would work as well but str.isfloat is more > > inline with the current string methods. > > Not really. There are no string methods to test for: > - ints > - floats > - complex numbers > - fractions > - decimals > you are expected to just try to convert and catch the exception if it > occurs (EAFP). So this would be new. As I have mentioned above, EAFP is fine but you have to apply it twice. str.float accomplishes the same with 1 line of code. num = float(s) if s.float() else int(s)

On Sat, Oct 02, 2021 at 01:06:46PM -0000, Debashish Palit wrote: [...]
Why a string? That's an unusual API. The more usual API would be: str (any base) --> int or float int or float --> str (any base) Not that it matters. Your "isfloat()" function doesn't help you. # Base 12 number, as a string. "2ab9.6".isfloat() # returns None for not a float or an int (That's 4461.5 in decimal.) So you can't use your isfloat method in this case, and you don't need to. All you need to do is check whether there is a radix point "." in the string.
Because just storing the number loses information. If you need the *exact* input then just storing the results after conversion to float or int has lost detail: int(" 123_456 ") # returns 123456 float(" +2.5000000000 ") # returns 2.5 float("7.3e5") # returns 730000.0 You can lose whitespace, underscores, leading plus sign, trailing zeroes, exponential format, and more. There is no way to recreate the exact input from the number. I don't know why you want to show the exact input. It is hard for me to see why it would be important. But **if** you do, and the input is a string, then keeping that string is the only way to preserve that exact input without losing detail. -- Steve

On Fri, Oct 01, 2021 at 08:56:39AM -0000, dpalit17@outlook.com wrote:
Given the design you gave for this function, how would you use it? s = input("Enter a number: ") # Or some other string three_way_flag = isfloat(s) # Or s.isfloat() if three_way_flag is None: raise ValueError("Not a number!") elif three_way_flag: num = int(s) else: num = float(s) Or did I get the true/false flags the wrong way around. I forget. Seems unnecessarily awkward and inefficient. Why not just have a function which takes a string and returns either an int or a float, whichever is appropriate? That function is pretty easy to write. And as Dennis mentions, there are many possible variations. What if you want a Decimal or a Fraction, or a complex number? What if you want to return a NAN instead of raising an exception? I'm also unsure when I might care about preserving the type of the number in this way. Typically I'm expecting to work with either floats or ints. If I'm working with ints, then a float would be an error, and I should just call `int(s)` and if the string contains a decimal point, that will be an error. If I'm working with floats, then just calling `float(s)` will have exactly the same effect as calling `int(s)` and then doing float arithmetic on it. Well, not *quite* exactly. s = '1234567890'*100 x = float(s)*1.0 y = int(s)*1.0 Calculating x will give the float INF; calculating y will raise OverflowError. So I think that this sort of function to preserve the type of the numeric string is going to have a very limited use. -- Steve

There is no need of a three_way_flag - just use a conditional expression instead of an if-elif-else block, str.isfloat uses the int() and float() functions, so, in your example, if float returns inf we can still return True (or maybe return None in this case too). If int() raises overflow error, then str.isfloat() would fail as well. Regarding use cases of str.isfloat, I have replied above.

A correction to my reply: int('1234567890' * 100) will not raise an overflow error, multiplying 1.0 with it raises the error. str.isfloat would still flag the string as an int and then it is upto the application code to deal with the overflow error.

On Sat, Oct 02, 2021 at 02:53:03AM -0000, Debashish Palit wrote:
There is no need of a three_way_flag - just use a conditional expression instead of an if-elif-else block,
Of course you need a three way flag if your function returns a three way flag. It returns False for ints, True for floats, and None for anything else. So the caller needs to handle three cases: - your function returns True, so call float(s) - your function returns False, so call int(s) - your function returns None, so handle the string some other way. How else could you do it?
str.isfloat uses the int() and float() functions,
Correct, which is why your function is wasteful and inefficient. If I call `isfloat('123')`, the function calls float, and throws the result away, so I have to call float *again*. So if people use this function, they are effectively doing: s = '123.0' # input is a string, from somewhere else float(s) # throw away the result num = float(s)
If int() raises overflow error
int() never raises OverflowError. -- Steve

Steven D'Aprano wrote: > On Sat, Oct 02, 2021 at 02:53:03AM -0000, Debashish Palit wrote: > > There is no need of a three_way_flag - just use a conditional > > expression instead of an if-elif-else block, > > Of course you need a three way flag if your function returns a three way > flag. It returns False for ints, True for floats, and None for anything > else. > So the caller needs to handle three cases: > - your function returns True, so call float(s) > - your function returns False, so call int(s) > - your function returns None, so handle the string some other way. > How else could you do it? Using a conditional expression, we can code it like this: num = float(s) if (c := s.isfloat()) else int(s) if c is False else 0 # any default Better still if we know its going to be a number, we can do - num = float(s) if s.isfloat() else int(s) > > str.isfloat uses the int() and float() functions, > > Correct, which is why your function is wasteful and inefficient. If I > call `isfloat('123')`, the function calls float, and throws the result > away, so I have to call float *again*. So if people use this function, > they are effectively doing: > s = '123.0' # input is a string, from somewhere else > float(s) # throw away the result > num = float(s) str.isfloat does more than just convert to float. Even if you are not converting to a float, str.isfloat is a good check for a valid number. We can simply do - if s.isfloat() is not None: # valid int or float ...

On Sat, Oct 02, 2021 at 01:21:46PM -0000, Debashish Palit wrote:
Using a conditional expression, we can code it like this: num = float(s) if (c := s.isfloat()) else int(s) if c is False else 0 # any default
Here is your three_way_flag: c := s.isfloat() Just because you called it the obfuscated name "c" (for character?) instead of a meaningful name, doesn't change the fact that it is a flag that can take three values, or that you have to use *two* conditional tests giving *three* branches to deal with it. We could write it as a lookup table with a dispatch function too: num = {True: float, False: int, None: lambda x: 0}[s.isfloat()](s) There are still three possible values for your flag, and three possible actions to take.
Better still if we know its going to be a number, we can do -
But you don't know it is going to be a number.
And then what? Is it a float or an int? if s.isfloat() is not None: if s.isfloat(): return float(s) else: return int(s) else: return 0 It's still a three way flag even if you calculate the flag twice. That just makes it even more wasteful and inefficient. -- Steve

Ok it is a 3 way flag, but the code is not awkward. 'c' is just a name I chose - it does not mean anything. The check for a valid number can be used on a list of strings - [float(s) for s in lst if s.isfloat() is not None] No 3 way flag here. Difficult to do with EAFP.

On Sun, Oct 3, 2021 at 1:55 AM Debashish Palit <dpalit17@outlook.com> wrote:
If you want to filter a list to just those which don't raise exceptions when you floatify them, just do that: def floatify(n): try: return float(n) except ValueError: return None [n for n in map(floatify, lst) if n is not None] Not everything has to be a built-in. The more specific it is to your purposes, the better to just write your own function. ChrisA

The floatify solution is a bit involved - using map inside a list comprehension. Usually list comprehensions replace the usage of map. Also floatify requires 5 extra lines of code (putting `return` on the same line is not a best practice). Why not do it with one simple line of code ? Debashish

On Sun, Oct 03, 2021 at 01:26:06AM -0000, Debashish Palit wrote:
Of course you can do it with one line of code. Nobody is telling you that you mustn't use your "isfloat()" function in your own code. Go right ahead. We're just pointing out why it is not likely to be made into a built in string method. - too narrow use: the good use cases for it are very small; - too specialized: it doesn't generalise to other numeric formats without re-writing the function; - awkward interface: it returns a three-way flag, True, False or None; - wrongly named: isfloat() doesn't return a True/False bool to tell you whether the string is a float, it returns three values to tell you whether it is a float, an int or neither; - duplicated effort: having called the method, you still have to call float() or int() again to actually get the result you actually want. -- Steve

There are plenty of use cases if you pause to think. The other objections are trivial. Even the simplest usage with the input() function is enough to warrant its inclusion, considering that there are other useless string methods. As I have had no support for the past few days, I quit the discussion.

I don't know how common it is to want to distinguish between string representations of integers and those of floats. It seems like a function that could have a million little variations: What if my boss says that now my input integers can have commas? Or have extra space added? Or if integer-valued floats should be considered integers? What if we run into localization issues with a commas-versus-periods-as-decimal-separator? What if we want to start accepting fractions like "22/7"? What if we find dollar signs in front? What if we want to return 0 or NaN in place of None? It seems to me that with all of these possible variations, it's best to spell out in your code exactly what to do for your individual use case, using try/except as necessary. That's not to say that you shouldn't make this function in your own code -- maybe you're personally writing dozens of scripts that use exactly this function. If so, great: add it to a personal utility library and import it when you need it. But I'm not sure it's worth the bloat of giving that same function to all Python users across the world whether they want it or not. By the way, if I were implementing something like this, I would probably instead write something like def parse_value(string): try: return int(string) except ValueError: pass try: return float(string) except ValueError: return None so that all of the parsing is together, and then elsewhere in the code write isinstance(number, float) rather than passing strings around and repeatedly parsing/re-parsing with some kind of isfloat(string) operation.

The method need not take care of every variation. Currently there is no method to check for a float in a string even without formatting. str.numeric or str.decimal don't work. str.isfloat would test unformatted strings for floats or ints just like the functions int() and float() convert strings of numbers. As for the use cases, I can think of 2: 1. When accepting user input with the input() function, you may get integers and not floats. If you just convert the strings to floats, you will get the result of a calculation as a float. Here the type of the input needs to be preserved. 2. A case that may come up often is passing numbers as strings to an instance method. After converting the number to a float, you may want to output the value in a repr method. Saving the precise type would help. The parse_value function would work as well but str.isfloat is more inline with the current string methods. Also string methods return either a boolean or a string and parse_value returns a number and is suited to a personal library. Why do you call it 'bloat'? It is just one function with a few lines of code. Other languages like Haskell have much bigger libraries.

On Sat, Oct 2, 2021 at 12:19 PM Debashish Palit <dpalit17@outlook.com> wrote:
Because your version of the function is slightly different from other people's versions. Making it part of the core language would require that it be right for everyone. Instead, just have the simple version in your own code, and it can be perfect for your usage. ChrisA

Having such a method in the core helps avoid writing the function repeatedly. (This would especially help beginners.) My version is suited to the core language as a string method. parse_value as given by Dennis Sweeney is suited to user code.

On Sat, Oct 02, 2021 at 02:17:32AM -0000, Debashish Palit wrote:
The method need not take care of every variation. Currently there is no method to check for a float in a string even without formatting.
Right, because no method is needed. If you want to convert something to a float (whether a string, or anything else), it is nearly always better to try to convert it: try: result = float(s) except TypeError: # Cannot be converted to a float. ... # some fallback routine This software pattern is called "Easier to Ask Forgiveness than Permission" and is usually more efficient and safer than the opposite pattern, "Look Before You Leap". https://devblogs.microsoft.com/python/idiomatic-python-eafp-versus-lbyl/ So the number of use-cases for your function are probably very few.
Can you give a real example of a case where you are doing calculations on a number provided as a string, but need to preserve the original format?
2. A case that may come up often is passing numbers as strings to an instance method.
Why pass your numbers to functions as *strings* if you want to do calculations with them?
If you need to preserve the exact input for the repr method, you should preserve the actual input. class MyClass: def __init__(self, astring): self._arg = astring self.number = float(astring) def __repr__(self): return 'MyClass(%s)' % self._arg
The parse_value function would work as well but str.isfloat is more inline with the current string methods.
Not really. There are no string methods to test for: - ints - floats - complex numbers - fractions - decimals you are expected to just try to convert and catch the exception if it occurs (EAFP). So this would be new. The existing string methods isdecimal, isdigit and isnumeric test for Unicode categories, for example: '\N{CIRCLED DIGIT THREE}'.isdigit() --> returns True '\N{CIRCLED DIGIT THREE}'.isdecimal() --> returns False '\N{ETHIOPIC NUMBER FIFTY}'.isnumeric() --> returns True '\N{ETHIOPIC NUMBER FIFTY}'.isdigit() --> returns False -- Steve

Steven D'Aprano wrote: > On Sat, Oct 02, 2021 at 02:17:32AM -0000, Debashish Palit wrote: > > The method need not take care of every variation. Currently there is > > no method to check for a float in a string even without formatting. > > Right, because no method is needed. If you want to convert something to > a float (whether a string, or anything else), it is nearly always > better to try to convert it: > try: > result = float(s) > except TypeError: > # Cannot be converted to a float. > ... # some fallback routine > This software pattern is called "Easier to Ask Forgiveness than > Permission" and is usually more efficient and safer than the opposite > pattern, "Look Before You Leap". > https://devblogs.microsoft.com/python/idiomatic-python-eafp-versus-lbyl/ > So the number of use-cases for your function are probably very few. I am not against EAFP. It should be used, but when you have decide between an int and a float, you would need to apply it twice. str.float is a convenience method wrapping that. > > > > When accepting user input with the input() function, you may get > > > > integers and not floats. If you just convert the strings to floats, > > you will get the result of a calculation as a float. Here the type of > > the input needs to be preserved. > > Can you give a real example of a case where you are doing calculations > on a number provided as a string, but need to preserve the original > format? Real example =========== Consider a number radix conversion software. It needs to accept the input number as a string (say '15A' in base 12). When we provide it a base 10 number, it would also be a string. If we are storing the base 10 equivalent of the input number, then we need to convert the input number to the correct type - float or int. Otherwise calculations may not be accurate - addition may yield a float when an int was expected. > > After converting the number to a float, you may want > > to output the value in a repr method. Saving the precise type would > > help. > > If you need to preserve the exact input for the repr method, you should > preserve the actual input. > class MyClass: > def __init__(self, astring): > self._arg = astring > self.number = float(astring) > def __repr__(self): > return 'MyClass(%s)' % self._arg Here you are storing the same info twice - as a string and as a number. Why not just store a number? > > The parse_value function would work as well but str.isfloat is more > > inline with the current string methods. > > Not really. There are no string methods to test for: > - ints > - floats > - complex numbers > - fractions > - decimals > you are expected to just try to convert and catch the exception if it > occurs (EAFP). So this would be new. As I have mentioned above, EAFP is fine but you have to apply it twice. str.float accomplishes the same with 1 line of code. num = float(s) if s.float() else int(s)

On Sat, Oct 02, 2021 at 01:06:46PM -0000, Debashish Palit wrote: [...]
Why a string? That's an unusual API. The more usual API would be: str (any base) --> int or float int or float --> str (any base) Not that it matters. Your "isfloat()" function doesn't help you. # Base 12 number, as a string. "2ab9.6".isfloat() # returns None for not a float or an int (That's 4461.5 in decimal.) So you can't use your isfloat method in this case, and you don't need to. All you need to do is check whether there is a radix point "." in the string.
Because just storing the number loses information. If you need the *exact* input then just storing the results after conversion to float or int has lost detail: int(" 123_456 ") # returns 123456 float(" +2.5000000000 ") # returns 2.5 float("7.3e5") # returns 730000.0 You can lose whitespace, underscores, leading plus sign, trailing zeroes, exponential format, and more. There is no way to recreate the exact input from the number. I don't know why you want to show the exact input. It is hard for me to see why it would be important. But **if** you do, and the input is a string, then keeping that string is the only way to preserve that exact input without losing detail. -- Steve

On Fri, Oct 01, 2021 at 08:56:39AM -0000, dpalit17@outlook.com wrote:
Given the design you gave for this function, how would you use it? s = input("Enter a number: ") # Or some other string three_way_flag = isfloat(s) # Or s.isfloat() if three_way_flag is None: raise ValueError("Not a number!") elif three_way_flag: num = int(s) else: num = float(s) Or did I get the true/false flags the wrong way around. I forget. Seems unnecessarily awkward and inefficient. Why not just have a function which takes a string and returns either an int or a float, whichever is appropriate? That function is pretty easy to write. And as Dennis mentions, there are many possible variations. What if you want a Decimal or a Fraction, or a complex number? What if you want to return a NAN instead of raising an exception? I'm also unsure when I might care about preserving the type of the number in this way. Typically I'm expecting to work with either floats or ints. If I'm working with ints, then a float would be an error, and I should just call `int(s)` and if the string contains a decimal point, that will be an error. If I'm working with floats, then just calling `float(s)` will have exactly the same effect as calling `int(s)` and then doing float arithmetic on it. Well, not *quite* exactly. s = '1234567890'*100 x = float(s)*1.0 y = int(s)*1.0 Calculating x will give the float INF; calculating y will raise OverflowError. So I think that this sort of function to preserve the type of the numeric string is going to have a very limited use. -- Steve

There is no need of a three_way_flag - just use a conditional expression instead of an if-elif-else block, str.isfloat uses the int() and float() functions, so, in your example, if float returns inf we can still return True (or maybe return None in this case too). If int() raises overflow error, then str.isfloat() would fail as well. Regarding use cases of str.isfloat, I have replied above.

A correction to my reply: int('1234567890' * 100) will not raise an overflow error, multiplying 1.0 with it raises the error. str.isfloat would still flag the string as an int and then it is upto the application code to deal with the overflow error.

On Sat, Oct 02, 2021 at 02:53:03AM -0000, Debashish Palit wrote:
There is no need of a three_way_flag - just use a conditional expression instead of an if-elif-else block,
Of course you need a three way flag if your function returns a three way flag. It returns False for ints, True for floats, and None for anything else. So the caller needs to handle three cases: - your function returns True, so call float(s) - your function returns False, so call int(s) - your function returns None, so handle the string some other way. How else could you do it?
str.isfloat uses the int() and float() functions,
Correct, which is why your function is wasteful and inefficient. If I call `isfloat('123')`, the function calls float, and throws the result away, so I have to call float *again*. So if people use this function, they are effectively doing: s = '123.0' # input is a string, from somewhere else float(s) # throw away the result num = float(s)
If int() raises overflow error
int() never raises OverflowError. -- Steve

Steven D'Aprano wrote: > On Sat, Oct 02, 2021 at 02:53:03AM -0000, Debashish Palit wrote: > > There is no need of a three_way_flag - just use a conditional > > expression instead of an if-elif-else block, > > Of course you need a three way flag if your function returns a three way > flag. It returns False for ints, True for floats, and None for anything > else. > So the caller needs to handle three cases: > - your function returns True, so call float(s) > - your function returns False, so call int(s) > - your function returns None, so handle the string some other way. > How else could you do it? Using a conditional expression, we can code it like this: num = float(s) if (c := s.isfloat()) else int(s) if c is False else 0 # any default Better still if we know its going to be a number, we can do - num = float(s) if s.isfloat() else int(s) > > str.isfloat uses the int() and float() functions, > > Correct, which is why your function is wasteful and inefficient. If I > call `isfloat('123')`, the function calls float, and throws the result > away, so I have to call float *again*. So if people use this function, > they are effectively doing: > s = '123.0' # input is a string, from somewhere else > float(s) # throw away the result > num = float(s) str.isfloat does more than just convert to float. Even if you are not converting to a float, str.isfloat is a good check for a valid number. We can simply do - if s.isfloat() is not None: # valid int or float ...

On Sat, Oct 02, 2021 at 01:21:46PM -0000, Debashish Palit wrote:
Using a conditional expression, we can code it like this: num = float(s) if (c := s.isfloat()) else int(s) if c is False else 0 # any default
Here is your three_way_flag: c := s.isfloat() Just because you called it the obfuscated name "c" (for character?) instead of a meaningful name, doesn't change the fact that it is a flag that can take three values, or that you have to use *two* conditional tests giving *three* branches to deal with it. We could write it as a lookup table with a dispatch function too: num = {True: float, False: int, None: lambda x: 0}[s.isfloat()](s) There are still three possible values for your flag, and three possible actions to take.
Better still if we know its going to be a number, we can do -
But you don't know it is going to be a number.
And then what? Is it a float or an int? if s.isfloat() is not None: if s.isfloat(): return float(s) else: return int(s) else: return 0 It's still a three way flag even if you calculate the flag twice. That just makes it even more wasteful and inefficient. -- Steve

Ok it is a 3 way flag, but the code is not awkward. 'c' is just a name I chose - it does not mean anything. The check for a valid number can be used on a list of strings - [float(s) for s in lst if s.isfloat() is not None] No 3 way flag here. Difficult to do with EAFP.

On Sun, Oct 3, 2021 at 1:55 AM Debashish Palit <dpalit17@outlook.com> wrote:
If you want to filter a list to just those which don't raise exceptions when you floatify them, just do that: def floatify(n): try: return float(n) except ValueError: return None [n for n in map(floatify, lst) if n is not None] Not everything has to be a built-in. The more specific it is to your purposes, the better to just write your own function. ChrisA

The floatify solution is a bit involved - using map inside a list comprehension. Usually list comprehensions replace the usage of map. Also floatify requires 5 extra lines of code (putting `return` on the same line is not a best practice). Why not do it with one simple line of code ? Debashish

On Sun, Oct 03, 2021 at 01:26:06AM -0000, Debashish Palit wrote:
Of course you can do it with one line of code. Nobody is telling you that you mustn't use your "isfloat()" function in your own code. Go right ahead. We're just pointing out why it is not likely to be made into a built in string method. - too narrow use: the good use cases for it are very small; - too specialized: it doesn't generalise to other numeric formats without re-writing the function; - awkward interface: it returns a three-way flag, True, False or None; - wrongly named: isfloat() doesn't return a True/False bool to tell you whether the string is a float, it returns three values to tell you whether it is a float, an int or neither; - duplicated effort: having called the method, you still have to call float() or int() again to actually get the result you actually want. -- Steve

There are plenty of use cases if you pause to think. The other objections are trivial. Even the simplest usage with the input() function is enough to warrant its inclusion, considering that there are other useless string methods. As I have had no support for the past few days, I quit the discussion.
participants (6)
-
Chris Angelico
-
Debashish Palit
-
Dennis Sweeney
-
dpalit17@outlook.com
-
Jeremiah Paige
-
Steven D'Aprano