[Tutor] Limitation of int() in converting strings
Oscar Benjamin
oscar.j.benjamin at gmail.com
Thu Dec 27 18:13:44 CET 2012
On 24 December 2012 04:42, eryksun <eryksun at gmail.com> wrote:
> On Sat, Dec 22, 2012 at 12:57 PM, Oscar Benjamin
> <oscar.j.benjamin at gmail.com> wrote:
>>>>
>>>> def make_int(obj):
>>>> '''Coerce str, float and int to int without rounding error
>>>> Accepts strings like '4.0' but not '4.1'
>>>> '''
>>>> fnum = float('%s' % obj)
>>>> inum = int(fnum)
>>>> assert inum == fnum
>>>> return inum
>>>
>>> Well, that function is dangerously wrong. In no particular order,
>>> I can find four bugs and one design flaw.
>>
>> I expected someone to object to this function. I had hoped that they
>> might also offer an improved version, though. I can't see a good way
>> to do this without special casing the treatment of some or other type
>> (the obvious one being str).
>
> Strings don't implement __int__ or __trunc__; they aren't numbers, so
> why not special case them?
I hadn't realised that. Does the int(obj) function use isinstance(obj,
str) under the hood?
> You can parse strings with obj =
> Decimal(obj) (this uses a regex). Then for all inputs set inum =
> int(obj) and raise ValueError if inum != obj.
It had occurred to me that this would be the obvious fix for the issue
with large numbers. The result is:
from decimal import Decimal
def int_decimal(x):
if isinstance(x, str):
x = Decimal(x)
ix = int(x)
if ix != x:
raise ValueError('Not an integer: %s' % x)
return ix
Probably what I more often want, though, is a function that simply
refuses to handle real-valued types as inputs. That way if a float
sneaks in I can choose the appropriate rounding function (or bug fix)
at the source of the number. I'm not sure what's the best way to
detect real-valued types. At least for the stdlib using the numbers
module works:
from numbers import Integral
def int_(x):
if not isinstance(x, (Integral, str)):
raise TypeError('Need Integral: use round() or trunc()')
return int(x)
Oscar
More information about the Tutor
mailing list