Python, определите, должна ли строка быть преобразована в Int или Float

Я хочу преобразовать строку в максимально плотный тип данных: int или float.

У меня есть две строки:

value1="0.80"     #this needs to be a float
value2="1.00"     #this needs to be an integer.

Как я могу определить, что value1 должен быть Float и value2 должно быть целым числом в Python?

5 ответов


def isfloat(x):
    try:
        a = float(x)
    except ValueError:
        return False
    else:
        return True

def isint(x):
    try:
        a = float(x)
        b = int(a)
    except ValueError:
        return False
    else:
        return a == b

Python float объект is_integer метод:

from ast import literal_eval
def parses_to_integer(s):
    val = literal_eval(s)
    return isinstance(val, int) or (isinstance(val, float) and val.is_integer())

def coerce(x):
    try:
        a = float(x)
        b = int(x)
        if a == b:
            return b
        else:
            return a
    except:
        raise ValueError("failed to coerce str to int or float")

мне пришлось вести дело обеспечения '1.0' преобразуется в '1', Когда я пытался определить различия между двумя XML-документами. Поэтому я написал эту функцию, чтобы помочь мне. Я также думаю, что некоторые другие решения потерпят неудачу, когда рассматриваемый строковый литерал будет "True" или "False". Во всяком случае, для меня эта функция работает очень хорошо. Я надеюсь, что это поможет и вам.

from ast import literal_eval

def convertString(s):
    '''
    This function will try to convert a string literal to a number or a bool
    such that '1.0' and '1' will both return 1.

    The point of this is to ensure that '1.0' and '1' return as int(1) and that
    'False' and 'True' are returned as bools not numbers.

    This is useful for generating text that may contain numbers for diff
    purposes.  For example you may want to dump two XML documents to text files
    then do a diff.  In this case you would want <blah value='1.0'/> to match
    <blah value='1'/>.

    The solution for me is to convert the 1.0 to 1 so that diff doesn't see a
    difference.

    If s doesn't evaluate to a literal then s will simply be returned UNLESS the
    literal is a float with no fractional part.  (i.e. 1.0 will become 1)

    If s evaluates to float or a float literal (i.e. '1.1') then a float will be
    returned if and only if the float has no fractional part.

    if s evaluates as a valid literal then the literal will be returned. (e.g.
    '1' will become 1 and 'False' will become False)
    '''


    if isinstance(s, str):
        # It's a string.  Does it represnt a literal?
        #
        try:
            val = literal_eval(s)
        except:
            # s doesn't represnt any sort of literal so no conversion will be
            # done.
            #
            val = s
    else:
        # It's already something other than a string
        #
        val = s

    ##
    # Is the float actually an int? (i.e. is the float 1.0 ?)
    #
    if isinstance(val, float):
        if val.is_integer(): 
            return int(val)

        # It really is a float
        return val

    return val

выход единичного теста этой функции производит:

convertString("1")=1; we expect 1
convertString("1.0")=1; we expect 1
convertString("1.1")=1.1; we expect 1.1
convertString("010")=8; we expect 8
convertString("0xDEADBEEF")=3735928559; we expect 3735928559
convertString("hello")="hello"; we expect "hello"
convertString("false")="false"; we expect "false"
convertString("true")="true"; we expect "true"
convertString("False")=False; we expect False
convertString("True")=True; we expect True
convertString(sri.gui3.xmlSamples.test_convertString.A)=sri.gui3.xmlSamples.test_convertString.A; we expect sri.gui3.xmlSamples.test_convertString.A
convertString(<function B at 0x7fd9e2f27ed8>)=<function B at 0x7fd9e2f27ed8>; we expect <function B at 0x7fd9e2f27ed8>
convertString(1)=1; we expect 1
convertString(1.0)=1; we expect 1
convertString(1.1)=1.1; we expect 1.1
convertString(3735928559)=3735928559; we expect 3735928559
convertString(False)=False; we expect False
convertString(True)=True; we expect True

тестовый код следующим образом:

import unittest

# just  class for testing that the class gets returned unmolested.
#
class A: pass

# Just a function
#
def B(): pass

class Test(unittest.TestCase):


    def setUp(self):
        self.conversions = [
            # input      | expected
            ('1'         ,1         ),
            ('1.0'       ,1         ), # float with no fractional part
            ('1.1'       ,1.1       ),
            ('010'       ,8         ), # octal
            ('0xDEADBEEF',0xDEADBEEF), # hex
            ('hello'     ,'hello'   ),
            ('false'     ,'false'   ),
            ('true'      ,'true'    ),
            ('False'     ,False     ), # bool
            ('True'      ,True      ), # bool
            (A           ,A         ), # class
            (B           ,B         ), # function
            (1           ,1         ),
            (1.0         ,1         ), # float with no fractional part
            (1.1         ,1.1       ),
            (0xDEADBEEF  ,0xDEADBEEF),
            (False       ,False     ),
            (True        ,True      ),
        ]


    def testName(self):
        for s,expected in self.conversions:
            rval = convertString(s)
            print 'convertString({s})={rval}; we expect {expected}'.format(**locals())
            self.assertEqual(rval, expected)


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

вот интересное решение с использованием eval(). Примечание: использование eval очень опасно и не рекомендуется в производственных средах или где-либо, что eval() может получить пользовательский ввод! Считайте это только академически интересным ответом.

def get_string_type(x):
    if type(x) != str:
        raise ValueError('Input must be a string!')
    try:
        string_type = type(eval(x))
    except NameError:
        string_type = str
    return string_type

поскольку Eval рассматривает строку как необработанный код, это работает для любого типа, который вы можете ввести в repl. Пример

>>> from decimal import Decimal
>>> my_test_string = 'Decimal(0.5)'
>>> type(my_test_string)
<class 'str'>
>>> get_string_type(my_test_string)
<class 'decimal.Decimal'>