【发布时间】:2011-01-17 14:23:37
【问题描述】:
我是 python 新手,刚刚写了这个模块级函数:
def _interval(patt):
""" Converts a string pattern of the form '1y 42d 14h56m'
to a timedelta object.
y - years (365 days), M - months (30 days), w - weeks, d - days,
h - hours, m - minutes, s - seconds"""
m = _re.findall(r'([+-]?\d*(?:\.\d+)?)([yMwdhms])', patt)
args = {'weeks': 0.0,
'days': 0.0,
'hours': 0.0,
'minutes': 0.0,
'seconds': 0.0}
for (n,q) in m:
if q=='y':
args['days'] += float(n)*365
elif q=='M':
args['days'] += float(n)*30
elif q=='w':
args['weeks'] += float(n)
elif q=='d':
args['days'] += float(n)
elif q=='h':
args['hours'] += float(n)
elif q=='m':
args['minutes'] += float(n)
elif q=='s':
args['seconds'] += float(n)
return _dt.timedelta(**args)
我的问题是这里的 for 循环,即长 if elif 块,我想知道是否有更 Pythonic 的方法。
所以我将函数重写为:
def _interval2(patt):
m = _re.findall(r'([+-]?\d*(?:\.\d+)?)([yMwdhms])', patt)
args = {'weeks': 0.0,
'days': 0.0,
'hours': 0.0,
'minutes': 0.0,
'seconds': 0.0}
argsmap = {'y': ('days', lambda x: float(x)*365),
'M': ('days', lambda x: float(x)*30),
'w': ('weeks', lambda x: float(x)),
'd': ('days', lambda x: float(x)),
'h': ('hours', lambda x: float(x)),
'm': ('minutes', lambda x: float(x)),
's': ('seconds', lambda x: float(x))}
for (n,q) in m:
args[argsmap[q][0]] += argsmap[q][1](n)
return _dt.timedelta(**args)
我使用 timeit 模块测试了这两个代码的执行时间,发现第二个代码花费了大约 5-6 秒(默认重复次数)。
所以我的问题是:
1. 哪个代码被认为更 Python 化?
2. 写这个函数还有更pythonic的吗?
3. Python 性与编程的其他方面(如本例中的速度)之间的权衡如何?
附言我对优雅的代码有点强迫症。
已编辑_interval2在看到this answer后:
argsmap = {'y': ('days', 365),
'M': ('days', 30),
'w': ('weeks', 1),
'd': ('days', 1),
'h': ('hours', 1),
'm': ('minutes', 1),
's': ('seconds', 1)}
for (n,q) in m:
args[argsmap[q][0]] += float(n)*argsmap[q][1]
【问题讨论】:
-
到底为什么你会得到一个声称月份是 30 天的格式的时间增量,而实际上它们大多不是? :)
-
@Lennart 哈哈!是的,它们是多余的(即使是 365 天,如果您考虑闰年)。由于这些函数是关于时间间隔的,不用于计算未来的日期,所以我将它们作为附加功能保留。
-
不管它们是多余的,问题是它们是错误的。 2011 年 1 月 4 日和 2011 年 3 月 4 日之间的差值为 59 天。 2011 年 7 月 4 日和 2011 年 9 月 4 日之间的差异是 62 天。这两个差异都是 2 个月,但不是根据您的语法。计算未来日期是 timedeltas 的全部内容......
-
如果你想成为强迫症,那么请成为强迫症的错误。您发布的代码忽略了“5y 3”中的“3”,给出了一个“ValueError:float()的无效文字:”用于“-d”和“ValueError:float()的空字符串”以合理的外观“3.d”。此外,在 "_re" 和 "_dt" 中使用前导 _ 也不是 Pythonic。