Well, first off, it's called pop
for both list
and deque
, there is no popright
method on deque
s.
There is usually no meaningful performance difference between the two; every once in a while, a pop
on a deque
will cause a block deallocation (which has fixed overhead, it just makes that particular pop
a little more costly), and on a list
it can cause a realloc to shrink the underlying storage (which could end up being O(n)
, but only a tiny fraction of pop
s will cause it); asymptotically they're both O(1)
operations. If your list
is truly huge, then shrinks a lot you might get the occasional performance hiccup when it shrinks the underlying storage, but otherwise you're highly unlikely to notice a difference.
In answer to your question, deque
s are ever-so-slightly more efficient for use as stacks than list
s; if you're importing collections
anyway, and need a stack based structure, using a deque
will get you a tiny benefit (at least on CPython, can't speak to other implementation). But it's not really worth micro-optimizing here; the cost of importing collections
in the first place, and the cost of whatever useful code you execute based on this stack, likely dwarfs whatever tiny difference you'll see between list
and deque
for pop
s from the right. A simple ipython3
microbenchmark:
In [24]: %%timeit from collections import deque; s = deque([0] * 10000); onethousandnones = (None,) * 1000; pop = s.pop
...: ; push = s.append
...: for _ in onethousandnones:
...: pop()
...: for _ in onethousandnones:
...: push(0)
...:
...:
104 µs ± 7.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [25]: %%timeit s = [0] * 10000; onethousandnones = (None,) * 1000; pop = s.pop; push = s.append
...: for _ in onethousandnones:
...: pop()
...: for _ in onethousandnones:
...: push(0)
...:
...:
131 µs ± 8.93 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
So for a 1000 pops followed by 1000 pushes onto our stack, the deque
-based stack took 30 µs less (~15 ns less per operation). Now admittedly, if I remove the call parentheses to time the base overhead, the base overhead was around 50 µs, so the overhead specifically attributable to the list
is a significant fraction of the "minimum cost" of the deque
, but it's still pretty small in the context of a program that is presumably doing something useful, not just pushing and popping to a stack. And it's pretty stable regardless of size; for a stack that's 10x the size, the cost remains unchanged for both deque
and list
. If the stack was growing and shrinking so much that list
's amortized growth was kicking in, it might suffer a little more from the larger reallocations, but it's not normally something to worry about.