如何将包含dict列表的字符串转换为Python对象?

时间:2016-03-17 18:24:17

标签: python

ugly = "[{'ride': 1, 'pickup_time': datetime(2016, 3, 17, 15, 36, 35, 976202)},
         {'ride': 2, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 41, 35, 976202)}]"
# The actual variable contains a lot more dictionnaries...`

我想将丑陋的变量转换为真正的Python对象。 我尝试了json.loads()ast.literal_eval(),但仅限于一个字典。

这就是为什么在此之前,我试图将这个字符串拆分成几个字典,但是split()方法只有一个分隔符,所以看起来我需要一个REGEX才能做到这一点。

最简单的方法是什么?感谢。

5 个答案:

答案 0 :(得分:5)

首先,您应该在调用datetime方法时保持一致。在第一个词典中,您使用datetime和第二个datetime.datetime

无论你尝试使用Python eval字符串,你都不能同时datetime成为一个函数(第一个字典)和一个模块(第二个)。一旦你解决了这个问题,你将被迫使用邪恶的eval函数,因为json.loads而不是ast.litteral_eval都不接受函数。它们通常用于避免评估调用任何函数......

但如果这是您想要做的(并且您确定ugly不包含有害代码),则可行:

>>> ugly = "[{'ride': 1, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 36, 35, 976202)},{'ride': 2, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 41, 35, 976202)}]"
>>> import datetime
>>> dlist = eval(ugly)
>>> dlist
[{'ride': 1, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 36, 35, 976202)}, {'ride': 2, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 41, 35, 976202)}]

答案 1 :(得分:4)

您可以使用eval

a = eval(ugly)

此时a是一个词典列表,我相信你从那里得到它。

答案 2 :(得分:0)

您可以使用eval获取字典数组(修复datetime问题后),然后使用setattr将字典转换为实际的类对象:

from datetime import datetime

ugly = "[{'ride': 1, 'pickup_time': datetime(2016, 3, 17, 15, 36, 35, 976202)}, {'ride': 2, 'pickup_time': datetime(2016, 3, 17, 15, 41, 35, 976202)}]"
array = eval(ugly)

class Ride(object):
    pass

rides = []
for record in array:
    ride = Ride()
    for k, v in record.iteritems():
        setattr(ride, k, v)
    rides.append(ride)

for ride in rides:
    print "ride: {0}: pickup_time: {1}".format(ride.ride, ride.pickup_time)

答案 3 :(得分:0)

取决于您要导入datetime的方式:

import datetime

ugly = "[{'ride': 1, 'pickup_time': datetime(2016, 3, 17, 15, 36, 35, 976202)},{'ride': 2, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 41, 35, 976202)}]"
ugly = ugly.replace(" datetime(", " datetime.datetime(")
ugly = eval(ugly)

from datetime import datetime

ugly = "[{'ride': 1, 'pickup_time': datetime(2016, 3, 17, 15, 36, 35, 976202)},{'ride': 2, 'pickup_time': datetime.datetime(2016, 3, 17, 15, 41, 35, 976202)}]"
ugly = ugly.replace("datetime.", "")
ugly = eval(ugly)

无需事先清除ugly

,均可正常工作

答案 4 :(得分:0)

你可以通过提取datetimes及其键只调用这些配对上的eval来使用正则表达式来实现它:

from datetime import datetime
from ast import literal_eval
import re


def parse(ug):
    ug = ug.replace("datetime.", "")
    pairs = ("{{{}}}".format(p) for p in re.findall("('\w+':\s+datetime\(.*\))", ug))
    _parsed = literal_eval(re.sub("datetime\(.*\)","''", ug))
    for d in _parsed:
        d.update(eval(next(pairs)))
    return _parsed

列表将被订购,因此正确的配对将被放回正确的序列中:

In [4]: parse(ugly)
Out[4]: 
[{'pickup_time': datetime.datetime(2016, 3, 17, 15, 36, 35, 976202),
  'ride': 1},
 {'pickup_time': datetime.datetime(2016, 3, 17, 15, 41, 35, 976202),
  'ride': 2}]