Re: Behaviour of pop() for dictionaries
On 15/06/2021 21.37, BlindAnagram wrote: > On 15/06/2021 00:11, dn wrote: >> 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 >> ... > I think the difference here is that I know I am going to have to look at > the documentation for dequeue when I want to use it. For lists, sets and > dictionaries, I don't expect to look at the documentation and pop() > seemed a good bet for what I wanted to do. "What I expect" (aka 'dim/dusty recollection' or 'gut feel') is a good way to learn - match it with the Python REPL and a couple of experiments to 'prove' your expectation/recollection. Thereafter there is a far greater likelihood of "learning" - and remembering-correctly 'next time'... The other worthy technique in this field is "deliberate learning". Thus, spending some time studying the docs for the built-ins' functionality (and experimentation) to obviate the need to look-up that level of documentation. Contrary to the learning-practices of 'our day', these days there is a far lower reliance on memory, in favor of rapid-access to reference data, eg the Python docs and REPL's help(), etc. Accordingly, the 'bits' that we might think of as 'minimum knowledge' may be seen as somewhat "arbitrary". (actually it is called Curriculum Design, but given that there is no single application-area for Python there is no single curriculum either) No matter: we are completely correct, no question - and what would 'they' know anyway? PS we were also subject to the idea that intelligence/ability was largely genetic and thus only available in a fixed quantity - either one is 'good' at something, or not (full stop). These days we know ourselves (brains) to be more "plastic", and that with sufficient motivation and effort we can learn 'new stuff', regardless of whether we were 'good at it' yesterday! >> 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". > > My student days are well over (about 60 years over). Someone with an even longer beard than mine! We could compare walking sticks... Oh wait, aren't we talking about Python. I'm amazed at how stuff from 'history' is recyclable and becomes applicable to whichever is described as 'today'. Even 'new' things in computing! There's always something new to adapt, if not learn... ... > Yes, but we can still seek consistency where it is possible Trouble is, there are different ways of looking at 'stuff', and thus different dimensions of "consistent". Thus, dict methods try to be consistent to the way a dict behaves. Whereas being 'consistent' with other collections: sets, lists, strings, etc; comes second. Oops if not OOPs! >> 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'!). I still haven't recalled a single occasion when I've used set.pop() or dict.pop(). Was that because I didn't recall their availability at the right time, or does my mind simply not see that 'consistency' yours recognises? (not that it matters particularly) >> 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... > > I don't like 'pop's at all since it meant that a valve had exploded on > the Ferranti Pegasus that was my first encounter with computers. That does pre-date the prehistoric computers I managed to play-with! There's apparently one in LON's Science Museum. Don't know if it was there when I last visited (c.15 years ago) - I do recall their Babbage implementations and an analog computer (looked like some torture rack) similar to one that my father used way, way, way-back. Similarly, considering it/another similar exhibit and talking with our friends about the 'joys' of using paper tape (and its talent for wrapping itself around anything and everything, except where you wanted it) and those of (assembler) programming delays in order to store data on rotating mag-drums. Those were the days! (or maybe not) -- Regards, =dn -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 15/06/2021 00:11, dn wrote: 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 think the difference here is that I know I am going to have to look at the documentation for dequeue when I want to use it. For lists, sets and dictionaries, I don't expect to look at the documentation and pop() seemed a good bet for what I wanted to do. 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". My student days are well over (about 60 years over). 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! Yes, but we can still seek consistency where it is possible 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... I don't like 'pop's at all since it meant that a valve had exploded on the Ferranti Pegasus that was my first encounter with computers. Brian -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 15/06/2021 01:36, Terry Reedy wrote: On 6/14/2021 5:18 PM, BlindAnagram wrote: I believe that consistency in how methods common to different types work is useful since it adds to the coherence of the language as a whole and avoids the need to remember special cases. Each collection class *is* a special case, and pop has to be adjusted to each. However, you seem to have missed an essential commonality. Lists and dicts are both subscripted classes. So the basic API is col.pop(sub), which removes and returns the sub item, whereas col[sub] leaves and returns. Lists have a special index, -1, the most commonly used, so that is the default. In fact, when I proposed list.pop(), I only proposed that, as I wanted pop to be the inverse of append, so a list could be used as a stack. Bad list subscripts are an error (unless one is slicing), whereas where dicts allow a default (when subscripted with the get method). Hence the optional default only for dicts. At one time, dicts, like sets, were unordered collections (of functional item pairs). dict.pop(), with no arg, could have been used to return a random 2-ple, but Guido is generally against having return types depend on arguments. So a new popxxx name was added. Note that deques have a popleft in addition to pop (right). Thanks for the interesting history. Having found that dict.pop() caused an error, I did wonder whether it should have returned a (key, value) pair but quickly came to the conclusion that this would be awful because it would be inconsistent with the normal value returned by pop(x). Sadly this did not result in any recollection that there was a popitem() :-( Brian -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 14Jun2021 09:39, BlindAnagram wrote: >However, d.pop(key, [default]) returns the value (or the default) and >consistency with other pops (a good thing in my view) would suggest >that d.pop() could return a random value, which would serve my purpose >when there is only one element. If you don't care what key was popped, maybe you want a set and not a dict? Just a thought. Cheers, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 6/14/2021 5:18 PM, BlindAnagram wrote: I believe that consistency in how methods common to different types work is useful since it adds to the coherence of the language as a whole and avoids the need to remember special cases. Each collection class *is* a special case, and pop has to be adjusted to each. However, you seem to have missed an essential commonality. Lists and dicts are both subscripted classes. So the basic API is col.pop(sub), which removes and returns the sub item, whereas col[sub] leaves and returns. Lists have a special index, -1, the most commonly used, so that is the default. In fact, when I proposed list.pop(), I only proposed that, as I wanted pop to be the inverse of append, so a list could be used as a stack. Bad list subscripts are an error (unless one is slicing), whereas where dicts allow a default (when subscripted with the get method). Hence the optional default only for dicts. At one time, dicts, like sets, were unordered collections (of functional item pairs). dict.pop(), with no arg, could have been used to return a random 2-ple, but Guido is generally against having return types depend on arguments. So a new popxxx name was added. Note that deques have a popleft in addition to pop (right). -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
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 -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 14/06/2021 20:43, Chris Angelico wrote: On Tue, Jun 15, 2021 at 5:41 AM BlindAnagram wrote: However, d.pop(key, [default]) returns the value (or the default) and consistency with other pops (a good thing in my view) would suggest that d.pop() could return a random value, which would serve my purpose when there is only one element. Is this actually important or are you just looking for a meaningless "inconsistency"? Dictionaries are fundamentally different from lists. Is it really that hard to use popitem? No I am not looking for meaningless inconsistency - just the opposite in fact - meaningful consistency. I believe that consistency in how methods common to different types work is useful since it adds to the coherence of the language as a whole and avoids the need to remember special cases. No it isn't hard to use popitem() but it evidently proved hard for me to remember that it was there. Brian -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On Tue, Jun 15, 2021 at 5:41 AM BlindAnagram wrote: > However, d.pop(key, [default]) returns the value (or the default) and > consistency with other pops (a good thing in my view) would suggest that > d.pop() could return a random value, which would serve my purpose when > there is only one element. > Is this actually important or are you just looking for a meaningless "inconsistency"? Dictionaries are fundamentally different from lists. Is it really that hard to use popitem? ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 14/06/2021 08:29, Greg Ewing wrote: On 14/06/21 4:19 am, BlindAnagram wrote: Am I missing the obvious way to obtain the value (or the key) from a dictionary that is known to hold only one item? v = d.popitem()[1] Thanks, Greg, I missed that. More importantly, is there a good reason why we don't have d.pop() for dictionaries? My guess is because it's not generally useful to get an returns the value arbitrary value from a dict without its corresponding key. Hence the existence of popitem(). However, d.pop(key, [default]) returns the value (or the default) and consistency with other pops (a good thing in my view) would suggest that d.pop() could return a random value, which would serve my purpose when there is only one element. -- https://mail.python.org/mailman/listinfo/python-list
Behaviour of pop() for dictionaries
The pop() method exists for five mainstream data items and shows a range of different behaviours for each of them. But, of the five, pop for dictionaries is the only one for which the first parameter is required and this makes d.pop() for dictionaries an error rather than doing something useful. I came across this in trying to use this sequence for a dictionary : if len(d.keys()) == 1: v = d.pop() I found it surprising that this failed given how the pops for the other types work. So I then tried: v = d.values()[0] and this doesn't work either since dict_keys items don't accept indexing. So I was driven to use: v = list(d.values())[0] which seems to me a lot less intuitive (and messier) than d.pop(). These: v = next(iter(d.values())) v, = d.values() also seem poor substitutes for giving d.pop() for dictionaries a useful and intuitive purpose. Am I missing the obvious way to obtain the value (or the key) from a dictionary that is known to hold only one item? More importantly, is there a good reason why we don't have d.pop() for dictionaries? Brian -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
You can do the following: _,v = d.popitem() Or: key, value = d.popitem() Steve On Mon, 14 Jun 2021 at 20:10, Greg Ewing wrote: > On 14/06/21 4:19 am, BlindAnagram wrote: > > Am I missing the obvious way to obtain the value (or the key) from a > > dictionary that is known to hold only one item? > > v = d.popitem()[1] > > > More importantly, is there a good reason why we don't have d.pop() for > > dictionaries? > > My guess is because it's not generally useful to get an arbitrary > value from a dict without its corresponding key. Hence the existence > of popitem(). > > -- > Greg > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: Behaviour of pop() for dictionaries
On 14/06/21 4:19 am, BlindAnagram wrote: Am I missing the obvious way to obtain the value (or the key) from a dictionary that is known to hold only one item? v = d.popitem()[1] More importantly, is there a good reason why we don't have d.pop() for dictionaries? My guess is because it's not generally useful to get an arbitrary value from a dict without its corresponding key. Hence the existence of popitem(). -- Greg -- https://mail.python.org/mailman/listinfo/python-list