简体   繁体   English

python - 没有赋值的列表理解

[英]python - list comprehension without assignment

Today I was parsing a directory index with a list of paths to zip files using BeautifulSoup and came across an interesting thing.今天,我正在使用 BeautifulSoup 解析带有 zip 文件路径列表的目录索引,并遇到了一件有趣的事情。 Let's assume I would like to take all the href properties of the tags I got and put them directly into a Queue:假设我想获取我获得的标签的所有href属性并将它们直接放入队列中:

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

I've never run into a situation like this before where a comprehension could be used inline without assigning it to anything, just to generated another iterator through some routine call.我以前从未遇到过这样的情况,可以内联使用推导式而不将其分配给任何东西,只是为了通过一些例行调用生成另一个迭代器。 Is this considered bad practice?这被认为是不好的做法吗? Is it "pythonic", per se?它本身是“pythonic”吗? Was there a better one-liner to put all the items into the queue?是否有更好的单线将所有物品放入队列中?

This has been asked many times, eg, here and here .这已被多次询问,例如, herehere But it's an interesting question, though.不过,这是一个有趣的问题。 List comprehensions are meant to be used for something else.列表推导式旨在用于其他用途。

Other options include其他选项包括

  1. use map() - basically the same as your sample使用map() - 与您的示例基本相同
  2. use filter() - if your function returns None, you will get an empty list使用filter() - 如果你的函数返回 None,你会得到一个空列表
  3. Just a plain for -loop只是一个普通的for循环

while the plain loop is the preferable way to do it.而普通循环是最好的方法。 It is semantically correct in this case, all other ways, including list comprehension, abuse concepts for their side-effect.在这种情况下,它在语义上是正确的,所有其他方式,包括列表理解,滥用概念的副作用。

In Python 3.x, map() and filter() are generators and thus do nothing until you iterate over them.在 Python 3.x 中, map()filter()是生成器,因此在迭代它们之前什么都不做。 So we'd need, eg, a list(map(...)) , which makes it even worse.所以我们需要,例如,一个list(map(...)) ,这让它变得更糟。

If you think of it as a loop over the list returned by soup.findAll it would look like this:如果你把它看作是对 sounding.findAll 返回的列表的循环,它看起来像这样:

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

This is probably the more 'pythonic' form as 'explicit is better than implict'这可能是更“pythonic”的形式,因为“显式优于隐式”

There are many opinions on this thread, I can only speak from coding conventions at my organization.关于这个线程有很多意见,我只能从我组织的编码约定中发言。

there are many ways to affect a loop, but a key attribute of list comprehensions is that they create lists , with one item for each in the iterated over sequence.有很多方法可以影响循环,但列表推导式的一个关键属性是它们创建列表,在迭代序列中每个列表都有一个项目。

>>> import Queue
>>> q = Queue.Queue()
>>> [q.put(item) for item in range(5)]
[None, None, None, None, None]
>>>

this unused list is obviously wasteful.这个未使用的列表显然是浪费的。 As such, this construction, a list comprehension with unused return value;因此,这个结构是一个带有未使用返回值的列表推导式; is forbidden from appearing in our code base.禁止出现在我们的代码库中。 An explicit loop like above, or a generated combined with something that consumes it, for instance:像上面这样的显式循环,或者生成的与消耗它的东西相结合,例如:

>>> any(q.put(item) for item in xrange(5))
False
>>>

or just:要不就:

>>> for item in xrange(5):
...     q.put(item)
...
>>>

is required to pass review.需要通过审核。

Probably not a better one-liner, but I'd (personally) consider doing this instead of:可能不是更好的单线,但我(个人)考虑这样做而不是:

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

to be bad practice.是不好的做法。 Firstly, the one liner will generate a list full of [None] , which is likely more inefficient.首先,one liner 将生成一个充满[None]的列表,这可能效率更低。 Secondly, it's not immediately clear what the code is doing;其次,不能立即清楚代码在做什么; seeing a list comprehension generally implies the resultant list will be used in some way.看到列表推导式通常意味着将以某种方式使用结果列表。

You can use any() the way it's recommended here , in the latest versions of Python在最新版本的 Python 中,您可以按照此处推荐的方式使用 any()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM