13

今天我正在使用 BeautifulSoup 解析一个包含 zip 文件路径列表的目录索引,并遇到了一件有趣的事情。假设我想获取href标签的所有属性并将它们直接放入队列中:

q = Queue.Queue()
[q.put(tag['href']) for tag in soup.findAll('a')]

我以前从未遇到过这样的情况,即可以内联使用推导而不将其分配给任何东西,只是通过一些例行调用生成另一个迭代器。这被认为是不好的做法吗?它本身是“pythonic”吗?是否有更好的单行方式将所有项目放入队列中?

4

5 回答 5

15

这已被多次询问,例如,herehere。但这是一个有趣的问题。列表推导旨在用于其他用途。

其他选项包括

  1. 使用map()- 与您的样品基本相同
  2. 使用filter()- 如果你的函数返回 None,你将得到一个空列表
  3. 只是一个普通的for循环

而普通循环是最好的方法。在这种情况下,在语义上是正确的,所有其他方式,包括列表理解,滥用概念的副作用。

在 Python 3.x 中,map()并且filter()是生成器,因此在迭代它们之前什么都不做。因此,我们需要例如 a list(map(...)),这会使情况变得更糟。

于 2013-01-10T01:29:26.207 回答
8

关于这个线程有很多意见,我只能从我组织的编码约定中发言。

有很多方法可以影响循环,但列表推导的一个关键属性是它们创建列表,在迭代序列中每个项目都有一个。

>>> 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)
...
>>>

需要通过审核。

于 2013-01-10T01:50:44.420 回答
6

如果你认为它是一个对由 soup.findAll 返回的列表的循环,它看起来像这样:

for tag in soup.findAll('a'):
    q.put(tag['href'])

这可能是更“pythonic”的形式,因为“显式优于隐式”

于 2013-01-10T01:25:02.560 回答
2

可能不是更好的单线,但我(个人)会考虑这样做而不是:

for tag in soup.findAll('a'):
    q.put(tag['href'])

是不好的做法。首先,一个班轮将生成一个充满 的列表[None],这可能效率更低。其次,不清楚代码在做什么。看到列表理解通常意味着结果列表将以某种方式使用。

于 2013-01-10T01:26:38.180 回答
0

您可以在最新版本的 Python 中按照此处推荐的方式使用 any()

q = Queue.Queue()
any(q.put(tag['href']) for tag in soup.findAll('a'))
于 2020-09-20T18:24:31.343 回答