从配置文件中获取时间增量值的正确方法

时间:2014-03-18 19:52:18

标签: python config timedelta

我有这个配置文件,我有统计信息:迭代次数和时间增量对象。我试图找到一种评估这个值的pythonic和安全的方法。 所以配置文件看起来像这样(test_config.cfg):

[Section]

option1 = (6, datetime.timedelta(0, 9, 520000))
option2 = (4, datetime.timedelta(0, 8, 510000))

当我使用time.timedelta()时,RawConfigParser.set('Section', 'option', (i, t_delta))条目就到达那里t_delta只是两次操作之间的时间跨度,i是迭代次数。从配置中读取此值时,它们将作为字符串返回。我想评估他们最初的情况。我尝试过的是什么,但我觉得必须有一种更安全,相应的pythonic方式:

import ConfigParser
import datetime

config = ConfigParser.RawConfigParser()
config.read('test_config.cfg')

stats = config.get('Section', 'option1')

# The obvious way is with eval() but makes me very uncomfortable using it
iterations = eval(stats)[0] # 6
duration = eval(stats)[1] # 0:00:09.520000

# The ugly way is with stripping and splitting
duration_tuple = tuple(int(i) for i in stats.split('(')[-1].strip(')').split(','))
duration = datetime.timedelta(*duration_tuple)
iterations = int(stats.split(',')[0].lstrip('('))
print iterations # 6
print duration # 0:00:09.520000

那么还有更好的方法吗?最终有没有办法在设置配置时只使用timedelta对象使用的'元组'?与(0, 9, 520000)代替datetime.timedelta(0, 9, 520000)一样。通过这种方式,我可以轻松使用ast.literal_eval()。谢谢!

2 个答案:

答案 0 :(得分:1)

使用

RawConfigParser.set('Section', 'option', (i, [t_delta.days, t_delta.seconds, t_delta.microseconds]))

您可以安排配置文件如下所示:

[Section]

option1 = [6, [0, 9, 520000]]
option2 = [4, [0, 8, 510000]]

然后你可以use json解析config.get返回的字符串:

import ConfigParser
import datetime
import json

config = ConfigParser.RawConfigParser()
config.read('test_config.cfg')

stats = config.get('Section', 'option1')
stats = json.loads(stats)
iterations = stats[0] # 6
duration = datetime.timedelta(*stats[1]) # 0:00:09.520000
print iterations # 6
print duration # 0:00:09.520000

这与使用ast.literal_eval基本相同。


以JSON格式解析配置文件:

但是,如果您有选项,我认为删除ConfigParser并使用JSON会更简单。例如,如果配置文件如下所示:

{"option2": [4, [0, 8, 510000]], "option1": [6, [0, 9, 520000]]}

然后将其读回Python,您可以使用:

import datetime
import json

with open('test_config.cfg', 'r') as f:
    config = json.load(f)
stats = config['option1']
iterations = stats[0] # 6
duration = datetime.timedelta(*stats[1]) # 0:00:09.520000
print iterations # 6
print duration # 0:00:09.520000

要将配置保存为JSON格式的文件:

config = {'option': [i, [t_delta.days, t_delta.seconds, t_delta.microseconds]}
with open('test_config.json', 'w') as f:
    json.dump(config, f)

答案 1 :(得分:0)

您可以将timedelta转换为秒(表示为浮点数,以便不会丢失部分秒数)。

RawConfigParser.set('Section', 'option1', '%s,%s' % (i, t_delta.total_seconds()))

现在你的部分看起来像是:

[Section]
option1 = (6, 9.520000)
option2 = (4, 8.510000)

您可以跳过使用eval:

stats = RawConfigParser.get('Section', 'option1').split(',')
iterations = int(stats[0]) # 6
duration = datetime.timedelta(seconds=float(stats[1])) # 0:00:09.520000

(编辑)

这是一个有用的示例,它将ast.literal_eval用于一个选项,并将split / cast用于另一个选项。 literal_eval风险更大,因为一个坏的演员可以运行比你想要的更多的代码,但仍然是合理的。 split / cast方法对它接受的输入要严格得多:

>>> from ConfigParser import RawConfigParser
>>> import datetime
>>> import ast
>>> 
>>> i = 6
>>> t_delta = datetime.timedelta(0, 9, 520000)
>>> 
>>> config = RawConfigParser()
>>> config.add_section('Section')
>>> config.set('Section', 'option_for_eval', (i, t_delta.total_seconds()))
>>> config.set('Section', 'option_for_cast', '%s,%f' % (i, t_delta.total_seconds()))
>>> config.write(open('/tmp/config.ini', 'w'))
>>> 
>>> config = RawConfigParser()
>>> config.read('/tmp/config.ini')
['/tmp/config.ini']
>>> option_for_eval = config.get('Section', 'option_for_eval')
>>> option_for_eval
'(6, 9.52)'
>>> i, t_delta = ast.literal_eval(option_for_eval)
>>> i, t_delta
(6, 9.52)
>>> 
>>> option_for_cast = config.get('Section', 'option_for_cast')
>>> stat = option_for_cast.split(',')
>>> i = int(stat[0])
>>> t_delta = datetime.timedelta(seconds=float(stat[1]))
>>> i, t_delta
(6, datetime.timedelta(0, 9, 520000))
>>>