加快 datetime.strptime

Posted

技术标签:

【中文标题】加快 datetime.strptime【英文标题】:Speeding up datetime.strptime 【发布时间】:2014-07-08 07:47:24 【问题描述】:

我正在使用以下代码从字符串中提取日期:

try:
    my_date = datetime.strptime(input_date, "%Y-%m-%d").date()
except ValueError:
    my_date = None

如果我运行 750,000 次,则需要 19.144 秒(由 cProfile 确定)。现在我用以下(丑陋的)代码替换它:

a= 1000 * int(input_date[0])
b=  100 * int(input_date[1])
c=   10 * int(input_date[2])
d=    1 * int(input_date[3])
year = a+b+c+d

c=   10 * int(input_date[5])
d=    1 * int(input_date[6])
month = c+d

c=   10 * int(input_date[8])
d=    1 * int(input_date[9])
day = c+d

try:
    my_date = date(year, month, day)
except ValueError:
    my_date = None

如果我运行 750,000 次,只需要 5.946 秒。但是,我发现代码真的很难看。有没有另一种快速从字符串中提取日期而不使用 strptime 的方法?

【问题讨论】:

使用timeit 进行计时赛,而不是cProfile。我并不是说卡片的掉落方式会有所不同,但肯定会更准确。 为什么不呢? year = int(input_date[:4])? try 的防范措施是什么 - 无效格式可能会在索引上失败。 @martijn:我使用 cProfile 的原因:我需要所有方法的近似结果,而不仅仅是这个。 @physicalattraction:但是在这篇文章中你说的是这个。如果您想运行时间试验来比较单个任务的方法,请使用timeit @physicalattraction: 并记录在案: strptime 确实比你丑陋的方法慢(大约 2 倍),因为它对输入进行了更多的验证。例如,它可以处理非零填充的月份和日期。 【参考方案1】:

是的,如果您放弃了很多灵活性和验证,有比datetime.strptime() 更快的方法来解析日期。 strptime() 允许带零填充和不带零填充的数字,它只匹配使用正确分隔符的字符串,而你的“丑陋”版本不匹配。

您应该始终使用timeit module 进行计时,它比这里的cProfile 准确得多。

确实,你的“丑陋”方法是strptime() 的两倍:

>>> from datetime import date, datetime
>>> import timeit
>>> def ugly(input_date):
...     a= 1000 * int(input_date[0])
...     b=  100 * int(input_date[1])
...     c=   10 * int(input_date[2])
...     d=    1 * int(input_date[3])
...     year = a+b+c+d
...     c=   10 * int(input_date[5])
...     d=    1 * int(input_date[6])
...     month = c+d
...     c=   10 * int(input_date[8])
...     d=    1 * int(input_date[9])
...     day = c+d
...     try:
...         my_date = date(year, month, day)
...     except ValueError:
...         my_date = None
... 
>>> def strptime(input_date):
...     try:
...         my_date = datetime.strptime(input_date, "%Y-%m-%d").date()
...     except ValueError:
...         my_date = None
... 
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import ugly as f')
4.21576189994812
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import strptime as f')
9.873773097991943

不过,您的方法可以改进;你可以使用切片:

>>> def slicing(input_date):
...     try:
...         year = int(input_date[:4])
...         month = int(input_date[5:7])
...         day = int(input_date[8:])
...         my_date = date(year, month, day)
...     except ValueError:
...         my_date = None
... 
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import slicing as f')
1.7224829196929932

现在它快了将近 6 倍。我还将int() 调用移到try - except 中,以便在将字符串转换为整数时处理无效输入。

您也可以使用str.split() 来获取零件,但这又会使其速度稍慢:

>>> def split(input_date):
...     try:
...         my_date = date(*map(int, input_date.split('-')))
...     except ValueError:
...         my_date = None
... 
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import split as f')
2.294667959213257

【讨论】:

以上是关于加快 datetime.strptime的主要内容,如果未能解决你的问题,请参考以下文章

工具加快你的效率 快捷键加快工具的效率 浏360览器篇

如何加快phpstorm更新git索引的速度

加快视图性能

如何加快sql查询执行速度?

加快插入 mdb

如何加快https的访问速度