这个蟒蛇可以缩短吗?

时间:2011-11-18 20:22:46

标签: python django

我倾向于在不牺牲运行效率的情况下,以最紧凑和简洁的方式表达代码。

这是我的代码:

p_audio = plate.parts.filter(content__iendswith=".mp3") 
p_video = not p_audio and plate.parts.filter(content__iendswith=".flv") 
p_swf =   not p_audio and not p_video and plate.parts.filter(content__iendswith=".swf") 
extra_context.update({
  'p_audio':  p_audio and p_audio[0],
  'p_video':  p_video and p_video[0],
  'p_swf':    p_swf and   p_swf[0]
})

是否有任何python / django大师可以大大缩短这段代码?

3 个答案:

答案 0 :(得分:3)

实际上,在追求紧凑性和效率的过程中,您已经设法提出了非常低效的代码。这是因为当您引用p_audionot p_audio时,会导致对该查询集进行评估 - 并且因为您之前没有对其进行切片,这意味着整个过滤器都来自数据库 - 例如所有以mp3结尾的plate个对象,依此类推。

在引用该查询的值之前,应确保首先为每个查询执行切片。由于您关心代码紧凑性,您可能希望首先使用[:1]进行切片,以获取单个对象的查询集:

p_audio = plate.parts.filter(content__iendswith=".mp3")[:1]
p_video = not p_audio and plate.parts.filter(content__iendswith=".flv") [:1]
p_swf =   not p_audio and not p_video and plate.parts.filter(content__iendswith=".swf")[:1]

其余的可以保持不变。

编辑添加因为您只对每个列表的第一个元素感兴趣,因为您只将[0]从每个元素传递到上下文中。但是在你的代码中,not p_audio引用原始的,未剪切的查询集:并且为了确定qs的真/假值,Django必须对它进行评估,它从数据库中获取所有匹配的元素并将它们转换为Python对象。由于您实际上并不想要这些对象,因此您需要做的工作量超出您的需要。

请注意,它并没有重新运行每个时间:这是第一次,因为在第一次评估之后,查询集在内部进行缓存。但正如我所说,这已经比你想要的更多了。

答案 1 :(得分:2)

除了减少冗余之外,使用新内容类型也更容易扩展。

kinds = (("p_audio", ".mp3"), ("p_video", ".flv"), ("p_swf", ".swf"))
extra_context.update((key, False) for key, _ in kinds)

for key, ext in kinds:
    entries = plate.parts.filter(content__iendswith=ext)
    if entries:
        extra_context[key] = entries[0]
        break

答案 2 :(得分:0)

只是将此作为另一个答案添加灵感来自Pyroscope的上述(因为我的编辑必须经过同行评审)

最新的化身是利用Django模板系统在引用时忽略了不存在的上下文项,因此下面的mp3等不需要初始化为False(或0)。因此,以下内容符合OP代码的所有功能。另一个优化是mp3等用作键名(而不是“p_audio”等)

for key in ['mp3','flv','swf'] :
  entries = plate.parts.filter(content__iendswith=key)[:1]
  extra_context[key] = entries and entries[0]
  if extra_context[key] :
     break