将生成器嵌入发电机中是Pythonic吗?

时间:2012-10-19 13:03:04

标签: python optimization generator list-comprehension

我需要构建空嵌套字典的大树,并想知道下面的代码是否是Pythonic:

dictionary_name = dict((year, dict((month, dict((day, []) for day in days))
                       for month in months)) for year in years)
  • 如果这是不好的做法,那么编写上述代码的Pythonic方法是什么?
  • 如果这不是不好的做法,我应该在哪里使用换行符来保持这个清晰易读的“Pythonic”。此外,嵌套时发电机的速度优势仍然存在吗?

注意:此问题也适用于列表推导。如果您认为我应该将此问题分解为多个问题,请告诉我。

4 个答案:

答案 0 :(得分:5)

你上面的内容对我来说有点过于密集......我实际上通常会避免像这样嵌套表达式,因为我很难记住它们是从内到外读取,还是从外面读取,或者通过某种方式读取奇怪的魔法随机方法。也就是说,我知道还有其他人写了很棒的python代码,有时会嵌套,我认为只要你没有嵌套得太深就可以了。

就个人而言,我可能会创建一个dict,它使用元组对其进行索引 - 我可能会考虑使用defaultdict

from collections import defaultdict
dictionary_name = defaultdict(list)
dictionary_name[(year,month,day)].append(data)
#your way would be:  `dictionary_name[year][month][day].append(data)`

这是(恕我直言)比你上面的代码更容易理解的代码(即更多的pythonic)。

如果您不想要defaultdict,可以使用itertools.product构建字典:

dictionary_name = dict( ( k,[] ) for k in it.product(years,months,days) )

dictionary_name = { k:[] for k in it.product(years,months,days) }  #py2.7+

答案 1 :(得分:5)

如果您不介意使用defaultdict,我会选择

from collections import defaultdict
import itertools
dd = defaultdict( defaultdict )
for y, m, d in itertools.product( years, months, days ):
    dd[y][m][d] = []

答案 2 :(得分:2)

列表理解的复杂性更多地取决于个人/开发。团队风格比纯粹的“被Pythonic”问题。对于这种情况,一个很好的潜在参考工具是Google Python Style Guide。他们的section on listcomps说:

  

可以用于简单的案例。

带有“决定”(即Google内部如何解决此问题):

  

可以用于简单的案例。每个部分必须适合一行:映射表达式,for子句,过滤器表达式。不允许使用多个for子句或过滤器表达式。当事情变得更复杂时,请使用循环。

就个人而言,我会选择嵌套的listcomps ,只要它们可以立即理解,否则会分解为多个部分,功能等。

您的问题的其他说明:

  • 是的,你可以在listcomps中进行换行,有时候有助于提高可读性。
  • 对于速度,答案是“它取决于”,并且可能更像是Stack Overflow的一个单独问题(我相信你会在这里找到一些好的起点)。如果不出意外:(1)确保这是一个瓶颈,然后(2)基准选择。

最终,风格问题是“运用你的判断力” - 只需考虑后来遇到你代码的其他开发人员。

答案 3 :(得分:0)

虽然我同意其他海报的说法,这个表达有点密集,如果你 打算写一些密集的东西,以另一种方式分解它可能是一个好主意。一点点缩进调整可以大大提高它的可读性:

dictionary_name = dict(
    (year, dict((month, dict((day, [])
                             for day in days))
                for month in months))
    for year in years)