今天我正在使用BeautifulSoup解析一个包含zip文件路径列表的目录索引,并且遇到了一件有趣的事情。让我们假设我想获取我得到的标签的所有href
属性并将它们直接放入队列中:
q = Queue.Queue()
[q.put(tag['href']) for tag in soup.findAll('a')]
我从来没有遇到这样的情况,在此之前可以使用内联而不将其分配给任何内容,只是通过一些例程调用生成另一个迭代器。这被认为是不好的做法吗?它本身就是“pythonic”吗?是否有更好的单行将所有项目放入队列?
答案 0 :(得分:11)
已多次询问此问题,例如here和here。但这是一个有趣的问题。列表推导意味着用于其他事情。
其他选项包括
map()
- 与您的示例基本相同filter()
- 如果您的函数返回None,您将获得一个空列表for
- 循环虽然普通循环是最好的方法。在这种情况下,它在语义上是正确的,所有其他方式,包括列表理解,滥用概念的副作用。
在Python 3.x中,map()
和filter()
是生成器,因此在迭代它们之前不执行任何操作。所以我们需要,例如,list(map(...))
,这会使情况变得更糟。
答案 1 :(得分:6)
如果你认为它是一个循环覆盖在汤.findAll返回的列表上,它将如下所示:
for tag in soup.findAll('a'):
q.put(tag['href'])
这可能是更“'pythonic'形式,因为'明确胜于暗示'
答案 2 :(得分:3)
关于这个帖子有很多意见,我只能说我组织的编码惯例。
有许多方法可以影响循环,但列表推导的一个关键属性是它们创建列表,迭代序列中每个都有一个项目。
>>> import Queue
>>> q = Queue.Queue()
>>> [q.put(item) for item in range(5)]
[None, None, None, None, None]
>>>
这个未使用的清单显然是浪费。因此,这种结构,具有未使用的返回值的列表理解;禁止出现在我们的代码库中。像上面这样的显式循环,或者生成与消耗它的东西相结合,例如:
>>> any(q.put(item) for item in xrange(5))
False
>>>
或只是:
>>> for item in xrange(5):
... q.put(item)
...
>>>
需要通过审核。
答案 3 :(得分:2)
可能不是一个更好的单行,但我(个人)考虑这样做而不是:
for tag in soup.findAll('a'):
q.put(tag['href'])
是不好的做法。首先,一个班轮将生成一个充满[None]
的列表,这可能效率更低。其次,目前还不清楚代码在做什么;看到列表理解通常意味着结果列表将以某种方式使用。
答案 4 :(得分:0)
在最新版本的Python中,您可以按照建议here的方式使用any()
q = Queue.Queue()
any(q.put(tag['href']) for tag in soup.findAll('a'))