19

The built-in function len() (https://docs.python.org/3/library/functions.html#len) returns "the length (the number of items) of an object", but this is not implemented for queue.Queue (https://docs.python.org/3/library/queue.html). Instead, queue.Queue has a qsize() method which returns the approximate size of a queue, when it clearly has a length; you can specify the maximum length of a Queue in the constructor. The similar collections.deque does work with len.

What are the reasons for not using the common len() for queue.Queue? Or: What would be the problems if qsize were instead named __len__ to enable the len() function?

cdjc
  • 1,039
  • 12
  • 24
  • 3
    Maybe because people expect `len` to return an accurate value, not an approximate one. And that it should be fast. To implement an accurate `__len__` the Queue would have to be temporarily locked to prevent additions & removals, which would impact performance. – PM 2Ring Dec 01 '17 at 01:40

1 Answers1

20

len() isn't implemented for queue.Queue because it would be an "attractive nuisance": something that only an expert should even consider using, but a "friendly name" would encourage non-experts to use it.

Unlike most sequence types (like list and deque), a queue.Queue is specifically intended to be used in multi-threaded contexts (and similarly for the multiprocessing module's queue type). While the number of items in a Queue certainly has a definite value at any particular time, it's impossible for user code to find out what that value is: between the time a call to .qsize() returns and your code can look at the returned value, any number of other threads (or processes, in the multiprocessing case) may have made any number of changes to the queue's contents.

So the only true thing that can be said about the value returned by .qsize() is that the Queue had that many values in it at some time in the past. By the time you can use the returned value, it may have arbitrarily more (or fewer) values in it.

Of course that's not so if you're only running one thread - but then there's no need to pay for the implementation complexity of a Queue (use a list or a deque instead).

Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • 1
    so why are `empty()` and `full()` implemented for a queue? – Charles Pehlivanian Dec 01 '17 at 01:58
  • 5
    They wouldn't implement `empty()` and `full()` if I had written them ;-) In the early days, the various optional `timeout=` arguments didn't exist, and `full()` and `empty()` were used in loops as _probabilistic_ gimmicks to make a decent guess at whether `.put()` or `.get()` were "likely to" succeed. Code using them (like code using `qsize()`) is as often as not prone to timing bugs. – Tim Peters Dec 01 '17 at 02:06
  • 3
    i not an expert, therefore a simple and least surprising `len()` sounds better to me than overthought `qsize()`. Specifics and possible inaccurateness of `len` could be explained in the help message and this should be sufficient for a programmer. – Nik O'Lai Feb 28 '21 at 09:15
  • I don't understand. The `len` function is overrideable: "*[The `len()` function will use the `__len__` method if present to query your object for its length.](https://stackoverflow.com/a/15114062/1201863)*" Why not just alias `__len__` to `qsize`? Then you get the exact same properties. It's not as if `if o.qsize() > 0: o.get()` is any more or less reliable than `if len(o) > 0: o.get()`. – Luc Dec 07 '21 at 09:58