преобразование списка строк Python в их тип

учитывая список строк Python, как я могу автоматически преобразовать их в правильный тип? Значение, если у меня есть:

["hello", "3", "3.64", "-1"]

Я бы хотел, чтобы это было преобразовано в список

["hello", 3, 3.64, -1]  

где первый элемент — это размешивание, второй — целое число, третий — число с плавающей запятой и четвертое — целое число.

как я могу это сделать? Спасибо.


person Community    schedule 18.05.2010    source источник


Ответы (7)


Без использования оценки:

def convert(val):
    constructors = [int, float, str]
    for c in constructors:
        try:
            return c(val)
        except ValueError:
            pass
person Ryan    schedule 18.05.2010
comment
Отличное решение (и безопасное!). Подход может быть легко распространен на любой тип данных. +1 - person Escualo; 18.05.2010

def tryEval(s):
  try:
    return eval(s, {}, {})
  except:
    return s

map(tryEval, ["hello", "3", "3.64", "-1"])

Делайте это только в том случае, если вы доверяете входным данным. Кроме того, имейте в виду, что он поддерживает не только литералы; арифметические выражения также будут оцениваться.

person jemfinch    schedule 18.05.2010
comment
Вы должны указать типы исключений (например, NameError, SyntaxError). - person tgray; 18.05.2010
comment
В целом да, но в этой реализации точно нет. Вы действительно хотите попытаться определить все исключения, которые могут быть вызваны eval? ZeroDivisionError, TypeError и, возможно, еще что-то, о чем я даже не думаю? - person jemfinch; 18.05.2010

Я сделал то же самое, используя метод json.loads

def f(l):
    for i in l:
        try:
            yield json.loads(i)
        except:
            yield i

Тест:

In [40]: l
Out[40]: ['hello', '3', '3.64', '-1']

In [41]: list(f(l))
Out[41]: ['hello', 3, 3.64, -1]
person ChillarAnand    schedule 17.11.2014

Если вас действительно интересуют только строки, числа с плавающей запятой и целые числа, я предпочитаю более подробный, менее оценочный

def interpret_constant(c):
    try:
        if str(int(c)) == c: return int(c)
    except ValueError:
        pass
    try:
        if str(float(c)) == c: return float(c)
    except ValueError:
        return c

test_list = ["hello", "3", "3.64", "-1"]

typed_list = [interpret_constant(x) for x in test_list]
print typed_list
print [type(x) for x in typed_list]
person msw    schedule 18.05.2010

На самом деле это не ответ, но я хотел указать, насколько это может быть важно, когда у вас есть база данных параметров со схемой ID, PAR, VAL. Например:

ID  PAR      VAL
001 velocity '123.45'
001 name     'my_name'
001 date     '18-dec-1978'

Эта схема подходит, когда вы не знаете, сколько параметров вам нужно сохранить для определенного ID. Недостатком является именно то, что все значения в VAL являются строками и должны быть преобразованы в правильный тип данных по запросу. Вы можете сделать это, добавив в схему четвертый столбец с именем TYPE, или вы можете использовать любой из предложенных подходов.

Хороший вопрос!

PS. Схема базы данных связана с одним из моих предыдущих вопросов.

person Escualo    schedule 18.05.2010

Вариант хорошего решения Райана для пользователей numpy:

def tonum( x ):
    """ -> int(x) / float(x) / None / x as is """
    if np.isscalar(x):  # np.int8 np.float32 ...
    # if isinstance( x, (int, long, float) ):
        return x
    try:
        return int( x, 0 )  # 0: "0xhex" too
    except ValueError:
        try:
            return float( x )  # strings nan, inf and -inf too
        except ValueError:
            if x == "None":
                return None
            return x

def numsplit( line, sep=None ):
    """ line -> [nums or strings ...] """
    return map( tonum, line.split( sep ))  # sep None: whitespace
person denis    schedule 19.05.2010

person    schedule
comment
Честно говоря, это лучшее решение, чем мое. - person jemfinch; 18.05.2010
comment
но evals довольно хакерские и подавленные - person msw; 18.05.2010
comment
Если это достаточно хорошо для компилятора Python, то это достаточно хорошо и для пользователя. - person Ignacio Vazquez-Abrams; 18.05.2010
comment
вы правы, я не знал о безопасной семантике ast.literal_eval bows - person msw; 18.05.2010
comment
Обратите внимание, что это примечание работает для таких случаев, как '01', где int('01')==1, но literal_eval выдает ошибку. В зависимости от варианта использования это означает, что literal_eval недостаточно. - person BurnNote; 26.01.2021