14

Suppose you have an iterable items containing items that should be put in a queue q. Of course you can do it like this:

for i in items:
    q.put(i)

But it feels unnecessary to write this in two lines - is that supposed to be pythonic? Is there no way to do something more readable - i.e. like this

q.put(*items)
IARI
  • 1,217
  • 1
  • 18
  • 35
  • 1
    The asterisk syntax is by some considered to be magic. The for-loop makes it clear to most people what is going on. – Stefan van den Akker Aug 13 '15 at 12:07
  • @StefanvandenAkker my very late answer to that argument: I suppose readability is very subjective - so shame on me for this type of question I guess. But with that said: the concept of packing/unpacking arguments with the asterisk has been part of python since - i believe the mid-2000's or so - and other languages have it as well. Even JavaScript had adopted the concept back then in 2015 with its spread operator - so I would argue that it isn't that unpopular. – IARI Mar 04 '21 at 20:12

3 Answers3

15

Using the built-in map function :

map(q.put, items)

It will apply q.put to all your items in your list. Useful one-liner.


For Python 3, you can use it as following :

list(map(q.put, items))

Or also :

from collections import deque
deque(map(q.put, items))

But at this point, the for loop is quite more readable.

FunkySayu
  • 7,641
  • 10
  • 38
  • 61
  • While I like that better a little bit, I don't think its really nice - it would be nicer in haskell, but thats just my taste. but the main problem is: this only works for python 2.x – IARI Aug 13 '15 at 11:48
  • @IARI, you could also do `[q.put(i) for i in items]`. But as I indicated in my answer, I would just use the code you have in your question. – Cyphase Aug 13 '15 at 11:50
  • 1
    Edited for python 3 support. – FunkySayu Aug 13 '15 at 11:53
  • Thanks - if find myself doing that a lot (composing list with map). But i think it's rather noisy and this defeats the purpose of readability a bit. Same with the list comprehension - I don't think its really readable. Both options seem to be a bit of an abuse. – IARI Aug 13 '15 at 11:56
  • Kind of. Side note : notice that sometime using list comprehension is faster than doing a for loop, and sometimes not. Here is an example of slower one-liner than a standard for loop : http://stackoverflow.com/questions/949098/python-split-a-list-based-on-a-condition/31448772#31448772 – FunkySayu Aug 13 '15 at 11:59
  • 2
    Comprehensions and `map` are intended for when you want the result, not as a way to have one-liner `for` loops; besides, in this case, you could just do `for i in items: q.put(i)`. – Cyphase Aug 13 '15 at 12:00
2

What's unreadable about that?

for i in items:
    q.put(i)

Readability is not the same as "short", and a one-liner is not necessarily more readable; quite often it's the opposite.

If you want to have a q.put(*items)-like API, consider making a short helper function, or subclassing Queue.

Cyphase
  • 11,502
  • 2
  • 31
  • 32
  • while you're absolutely right that short is not the same as readable, I would think if one does know python a bit `q.put(*items)` would be more readable, wouldn't you agree? in the end shorter is always more readable, if what the abbreviation does is clear to the literate reader. – IARI Aug 13 '15 at 11:50
  • @IARI, there's nothing wrong with that necessarily, though in the case of `Queue.put`, it wouldn't always make sense to be able to put more than one item at a time, due to blocking and timeouts. But if you wanted to write a helper function to do it for you (e.g. `put_items(q, *items)`; or in a subclass of `Queue`, `q.put_items(*items)`), I wouldn't have any objections to that. You could even call it `put`, as you said. Notice that I did mention both options in my answer :). – Cyphase Aug 13 '15 at 11:54
  • 1
    I guess I was partially responding to your question, and partially to FunkySayu's suggestion of `map(q.put, items)`. – Cyphase Aug 13 '15 at 11:57
  • right, I think the blocking is a better answer. I still feel a bit patronized as in "We're not letting you put iterables in queues because you might forget about blocking" ... But probably that is the main reason why the standart api doesn't have any way to do it, right? – IARI Aug 13 '15 at 12:01
  • @IARI, I don't know if that's why, but it's a good reason, especially when it's extremely trivial to do it yourself if you need to, as opposed to making the API even a little bit harder to use (or easier to misuse, as the case may be). – Cyphase Aug 13 '15 at 12:03
  • Would the recent down-voter like to comment on the reason for their action? :) – Cyphase Jul 16 '17 at 04:52
-3
q.extend(items)

Should be simple and Pythonic Enough

If you want it at the front of the queue

q.extendleft(items)

Python Docs:

https://docs.python.org/2/library/collections.html#collections.deque.extend

Frank He
  • 11
  • 2