Behaviour of pop() for dictionaries

dn PythonList at DancesWithMice.info
Mon Jun 14 19:11:31 EDT 2021


On 15/06/2021 09.18, BlindAnagram wrote:
> On 14/06/2021 20:43, Chris Angelico wrote:
>> On Tue, Jun 15, 2021 at 5:41 AM BlindAnagram
...

> No it isn't hard to use popitem() but it evidently proved hard for me to
> remember that it was there.

If that's a problem, you're going to love using deques with their
'popping from the left' and 'popping from the right' concepts!


I don't know if you are ComSc student or not, but there isn't even
consistency at the theoretical level. I first arrived at the concept of
"queuing" and "dequeuing" (NB the latter is not the same as the Python
Collections module "deque" library) whilst studying Queue Theory in
Operations Research. At about the same time, my ComSc studies took me
into "stacks".

Queues are known as FIFO constructs - "first-in, first-out".
Stacks are somewhat the opposite: LIFO - "last-in, first-out".

The "pop" operation was defined as taking the "next" item from the queue
or the "last" item from a stack (the opposite of "push"). However,
between queue and stack, the term "next" refers to opposite ends of the
(implementing in Python) list!

In fact, coming from a Burroughs mainframe, which ran on "stack
architecture" (cf IBM's multiplicity of "ALU registers"), it came as
something of a surprise when programming languages started allowing me
to "pop" elements that weren't at the LIFO-end of the 'list', eg
list.pop( 3 ) where len( list ) > 4!


Next consider how the terms "next" and "element" factor into the
thinking. If we consider a (Python) list there is an implied sequence of
elements based upon their relative position. Notice also that the basic
implementation of list.pop() is LIFO! Whereas, the definition of a set
involves no concept of sequence or order - only of membership (and that
the elements are "hashable"). Accordingly, a pop() operation returns an
"arbitrary value", cf 'next please'.

Similarly, a dict's keys are referred-to as hashable, with the idea of
"random access" to an element via its key (cf the "sequential access" of
a list). Thus, we can ask to pop() a dict, but only if we provide a key
- in which case, pop( key ) is the same as dict[ key ] except that the
key-value pair is also removed from the dict!

Recall though, it is possible to use list.pop() without any argument.
So, consistency has been thrown-out-the-window there as well.

Also, with LIFO in-mind, Python v3.7 brought a concept of 'sequence'
(population order) to dicts, and thus we now have this "guarantee" in
popitem() - and thus a memory-confusion for those of us who learned the
original "arbitrary" definition - confusion both of dict behavior and of
dict.popitem() specifically!


Worse confusion awaits (and referring to a conversation 'here' last
week) Python's pop() exhibits elements of both an "expression" and of a
"statement", ie it not only returns a value, but it affects
(?"side-effects") the underlying collection. Thus, no pop() for strings,
tuples, etc, because they are immutable collections!


The action of pop() is clearly inconsistent across types of collection.
It's effect is data-structure dependent because the purposes of those
structures are inherently different. "Consistency" would aid memory, but
"polymorphism" can only deliver functionality according to the
characteristics of the specific data-type!


Having entered the queue-of-life a long time ago, and shuffling ever
closer to 'the end of the line', this memory-challenged 'silver-surfer'
prefers to reserve pop() for straightforward stacks and lists, which
implies quite enough inconsistency, without trying to convolute my mind
to pop()-ing dicts, sets (or 'worse'!).

That said, whether I actually use dict.pop() or not, these 'features'
which are consistent in name but not necessarily in arguments or
effects, contribute to Python's great flexibility and power! Thank
goodness for help() and the Python docs...
-- 
Regards,
=dn


More information about the Python-list mailing list