pop method question

  • Thread starter Nicholas Parsons
  • Start date
N

Nicholas Parsons

Howdy Folks,

I was just playing around in IDLE at the interactive prompt and typed
in dir({}) for the fun of it. I was quite surprised to see a pop
method defined there. I mean is that a misnomer or what? From the
literature, pop is supposed to be an operation defined for a stack
data structure. A stack is defined to be an "ordered" list data
structure. Dictionaries in Python have no order but are sequences.
Now, does anyone know why the python core has this pop method
implemented for a dictionary type?

I realize that in this context it is used for removing a specific key
from the current dictionary object. But why call it pop and not
something more intuitive like remove or delete?

Thanks for the clarification in advance :).

--Nick
 
S

Stefan Scholl

Nicholas Parsons said:
I realize that in this context it is used for removing a specific key
from the current dictionary object. But why call it pop and not
something more intuitive like remove or delete?

I wasn't a python programmer back than, but I'd guess it's
because pop not just removes the key, it returns the value as
well.
 
P

Paul Rubin

Nicholas Parsons said:
I was just playing around in IDLE at the interactive prompt and typed
in dir({}) for the fun of it. I was quite surprised to see a pop
method defined there. I mean is that a misnomer or what? From the
literature, pop is supposed to be an operation defined for a stack
data structure. A stack is defined to be an "ordered" list data
structure. Dictionaries in Python have no order but are sequences.
Now, does anyone know why the python core has this pop method
implemented for a dictionary type?

Try typing:

help({}.pop)
 
S

Steven D'Aprano

Thanks, that gives a more details explanation of what the behavior is
but doesn't answer my question above :(

Just because pop can be defined for an ordered stack doesn't mean pop
can't be generalized to other data types too.

I personally don't see that pop has any advantage, especially since the
most useful example

while some_dict:
do_something_with(some_dict.pop())

doesn't work. Instead you have to write this:

for key in some_dict.keys():
# can't iterate over the dictionary directly!
do_something_with(some_dict.pop(key))

which is hardly any saving over:

for key in some_dict.keys():
# can't iterate over the dictionary directly!
do_something_with(some_dict[key])
del some_dict[key]


To my mind, having to supply a key to dict.pop makes it rather pointless.
 
S

Steven D'Aprano

aDict.pop(theKey)
'produce the value'

pop removes the key:value and produces the value
as results


Amazing. Absolutely amazing. Just goes to show that the ability to use
Linux doesn't require the sense to READ THE REST OF THE POST BEFORE
HITTING SEND. Not even the rest of the thread, just the post.

The Original Poster already knows that.
 
J

James Stroud

Steven said:
I personally don't see that pop has any advantage, especially since the
most useful example

while some_dict:
do_something_with(some_dict.pop())

doesn't work. Instead you have to write this:

for key in some_dict.keys():
# can't iterate over the dictionary directly!
do_something_with(some_dict.pop(key))

which is hardly any saving over:

for key in some_dict.keys():
# can't iterate over the dictionary directly!
do_something_with(some_dict[key])
del some_dict[key]


To my mind, having to supply a key to dict.pop makes it rather pointless.


I've used it in something like this and found it worthwhile:

for akey in dict1:
if some_condition(akey):
dict2[akey] = dict2.pop(akey)

Which necessitates a key is a little cleaner than your latter example.
 
P

Paul Rubin

James Stroud said:
for akey in dict1:
if some_condition(akey):
dict2[akey] = dict2.pop(akey)

Which necessitates a key is a little cleaner than your latter example.

Yeah, I also think removing keys from a dict while iterating over it
(like in Steven's examples) looks a bit dangerous dangerous.

Assuming you meant "dict1.pop" instead ot dict2.pop above, your
example might be written

dict2 = dict((k, dict1.pop(k)) for k in dict1 if some_condition(k))

avoiding some namespace pollution etc.
 
S

Steven D'Aprano

To my mind, having to supply a key to dict.pop makes it rather pointless.


I've used it in something like this and found it worthwhile:

for akey in dict1:
if some_condition(akey):
dict2[akey] = dict2.pop(akey)

Surely that's a no-op? You pop the value, than add it back again.

Or do you mean dict2[akey] = dict1.pop(akey)?

If so, are you sure that works? When I try it, I get "RuntimeError:
dictionary changed size during iteration". You would need to take a copy
of the keys and iterate over that.

for key in dict1.keys():
if some_condition(key):
dict2[key] = dict1.pop(key)
 
S

Steven D'Aprano

James Stroud said:
for akey in dict1:
if some_condition(akey):
dict2[akey] = dict2.pop(akey)

Which necessitates a key is a little cleaner than your latter example.

Yeah, I also think removing keys from a dict while iterating over it
(like in Steven's examples) looks a bit dangerous dangerous.

It is dangerous. That's why I didn't do it.

I very carefully iterated over a list, not the dictionary, and in fact put
in a comment explicitly saying that you can't iterate over the dictionary:

for key in some_dict.keys():
# can't iterate over the dictionary directly!
do_something_with(some_dict.pop(key))


If you try to iterate over the dictionary directly, you get a RuntimeError
exception when the dictionary changes size. Unfortunately, the exception
isn't raised until AFTER the dictionary has changed size.
.... D.pop(key)
....
1
Traceback (most recent call last):
{2: 2}


That's a gotcha to watch out for: the exception isn't raised until
the damage is done.


Assuming you meant "dict1.pop" instead ot dict2.pop above, your
example might be written

dict2 = dict((k, dict1.pop(k)) for k in dict1 if some_condition(k))

avoiding some namespace pollution etc.

You get a RuntimeError exception when dict1 changes size.

You know, if I were easily offended, I'd be offended that you accused _me_
of writing dangerous code when my code both worked and worked safely,
while your code failed and did damage when it did so (dict1 irretrievably
loses an item).

*wink*
 
J

James Stroud

Steven said:
To my mind, having to supply a key to dict.pop makes it rather pointless.

I've used it in something like this and found it worthwhile:

for akey in dict1:
if some_condition(akey):
dict2[akey] = dict2.pop(akey)

Surely that's a no-op? You pop the value, than add it back again.

Or do you mean dict2[akey] = dict1.pop(akey)?

If so, are you sure that works? When I try it, I get "RuntimeError:
dictionary changed size during iteration". You would need to take a copy
of the keys and iterate over that.

for key in dict1.keys():
if some_condition(key):
dict2[key] = dict1.pop(key)

Yes. You are right, both in the typo and using keys().

James
 
R

Raymond Hettinger

[Nicholas Parsons]
Dictionaries in Python have no order but are sequences.
Now, does anyone know why the python core has this pop method
implemented for a dictionary type?

I realize that in this context it is used for removing a specific key
from the current dictionary object. But why call it pop and not
something more intuitive like remove or delete?

The naming for pop() method followed from the naming of the previously
existing popitem() method. Neither "remove" nor "delete" would have
been a good name for a method that looked-up and returned a value as
well as mutating the dictionary. The word "pop" on the other hand
strongly suggests both retrieval and mutation.

The notion that "pop" is only defined for stack operations is somewhat
pedantic. We have also successfully used the name for sets, dicts,
and deques (success meaning that most people just "get it" and are
able to learn, use, read the name without difficultly).

The rationale for the pop() method was that the pattern "v=d[k]; del
d[k]" could be collapsed to a single call, eliminating a two
successive look-ups of the same key. Looking back, this rationale is
questionable because 1) the second lookup is not expensive because the
first lookup put the relevant hash entries in the cache, and 2) the
lookup/delete pattern for dictionaries does not seem to arise often in
practice (it does come-up every now and then in the context of set
operations).

There was also a notion that threaded programming would benefit by
having lookup-then-delete as an atomic transaction. It is unknown to
me whether that purported benefit has ever been realized.


Raymond Hettinger
 
A

Alex Martelli

Raymond Hettinger said:
The notion that "pop" is only defined for stack operations is somewhat
pedantic.

Worse: it's totally wrong. It's also defined for eyes, as a musical
genre, as a kind of soda, as an avant-garde artistic movement of the
'50s, for baloons, as a parent of the male persuasion, for email
reading, and moreover it's often used to refer to Persistent Organic
Pollutants or Points Of Presence -- not forgetting weasels, either.


Alex
 
A

Alex Martelli

Steven D'Aprano said:
while some_dict:
do_something_with(some_dict.pop())

doesn't work. Instead you have to write this:

You have to use .popitem for this -- that's what's it's for...


Alex
 
N

Nicholas Parsons

Hi Raymond,

Thank you for your clarification below. I was just using "remove"
and "delete" as possible alternatives to the name "pop" without much
contemplation. Like you say below, it begs the question as to why
not have two separate operations for dictionaries (retrieval of value
from key followed by deletion of key) instead of one method.

I'm not sure I agree with you said about the pedantic usage of pop.
I would rather have a term mean one thing instead of several causing
ambiguity. Just from my computer science background when I see pop
(), I think of a stack data structure. Why muddle the waters by
introducing another meaning for the term? There are plenty of other
words to use that could describe the behavior exhibited by the
dictionary operation of removing a key and returning its value. The
notion of a stack and pop() and push() methods for it are very
important from a historical perspective and is not just some fad.

But then again, there are other examples of ambiguity in the python
language such as allowing operators like '+' to be overloaded. Why
not just have a "add()" method like Java? Of course Java does cheat
a little by overloading the '+' operator for string objects but that
is a built-in feature of language. Also some people find '+' more
appealing to the eye than a method call like add() in their code.

Even in the case of C, we have some ambiguity with the dangling if
statement. So I guess you can't win for trying :).

Just call me a purist and think of me as someone who likes
consistency. Python is here to stay and no language is perfect...

--Nick

[Nicholas Parsons]
Dictionaries in Python have no order but are sequences.
Now, does anyone know why the python core has this pop method
implemented for a dictionary type?

I realize that in this context it is used for removing a specific key
from the current dictionary object. But why call it pop and not
something more intuitive like remove or delete?

The naming for pop() method followed from the naming of the previously
existing popitem() method. Neither "remove" nor "delete" would have
been a good name for a method that looked-up and returned a value as
well as mutating the dictionary. The word "pop" on the other hand
strongly suggests both retrieval and mutation.

The notion that "pop" is only defined for stack operations is somewhat
pedantic. We have also successfully used the name for sets, dicts,
and deques (success meaning that most people just "get it" and are
able to learn, use, read the name without difficultly).

The rationale for the pop() method was that the pattern "v=d[k]; del
d[k]" could be collapsed to a single call, eliminating a two
successive look-ups of the same key. Looking back, this rationale is
questionable because 1) the second lookup is not expensive because the
first lookup put the relevant hash entries in the cache, and 2) the
lookup/delete pattern for dictionaries does not seem to arise often in
practice (it does come-up every now and then in the context of set
operations).

There was also a notion that threaded programming would benefit by
having lookup-then-delete as an atomic transaction. It is unknown to
me whether that purported benefit has ever been realized.


Raymond Hettinger
 
M

MonkeeSage

Nick,

In regards to stack-like objects, pop() implies mutation of the
reciever and returning the item 'popped' off the stack. The same
_semantic_ meaning can be used for pop() regarding dictionaries, even
though the _implementation_ would be different: dict.pop(key) mutates
the reciever and returns the value associated with the key.

Regards,
Jordan
 
D

Dennis Lee Bieber

Nick,

In regards to stack-like objects, pop() implies mutation of the
reciever and returning the item 'popped' off the stack. The same
_semantic_ meaning can be used for pop() regarding dictionaries, even
though the _implementation_ would be different: dict.pop(key) mutates
the reciever and returns the value associated with the key.

"""
I before E
Except after C
Or when sounded as A
As in Neighbor and Weigh
"""

Or in Germanic, where the second vowel is sounded and the first is
silent

Bieber => Beee Berrr
Weiser => Weye Serrr




{and both are in my genealogy <G>}
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
B

Ben Finney

Dennis Lee Bieber said:
"""
I before E
Except after C
Or when sounded as A
As in Neighbor and Weigh
"""

Yes, like the "A" sound in "weird" or "ceiling".
 
A

Alex Martelli

Ben Finney said:
Yes, like the "A" sound in "weird" or "ceiling".

"ceiling" falls under the "except after C" exception.

"weird" is, of course, weird (as most of English)...


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top