加快datetime.strptime

phy*_*ion 4 python datetime profiling strptime python-2.7

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

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

如果我运行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
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*ers 5

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

您应该始终使用该timeit模块进行时间测试,它比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
Run Code Online (Sandbox Code Playgroud)

但是,您的方法可以得到改进。您可以使用切片:

>>> 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
Run Code Online (Sandbox Code Playgroud)

现在它快了将近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
Run Code Online (Sandbox Code Playgroud)