[Python-bugs-list] [ python-Bugs-639806 ] Optional argument for dict.pop() method

SourceForge.net noreply@sourceforge.net
Wed, 26 Feb 2003 08:54:25 -0800


Bugs item #639806, was opened at 2002-11-17 23:00
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=639806&group_id=5470

Category: Python Interpreter Core
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: Fernando Pérez (fer_perez)
Assigned to: Nobody/Anonymous (nobody)
Summary: Optional argument for dict.pop() method

Initial Comment:
I think the new dict.pop() method should support an optional argument for its return value when a key is not found. 

The current behavior (raising KeyError always) IMHO violates the principle of least surprise, since the very similar get() method _does_ support an optional return value. I am filing this as a bug on suggestion by Neil Schemenauer in c.l.py.

Here is a python proof of concept which I am using , implemented as a function. If this were accepted, similar behavior would need to be coded in the pop() method itself, which I suppose is part of the C core.

#----------------------------------------------------------------------------
class NotGiven: pass

def popkey(dct,key,default=NotGiven):
    """Return dct[key] and delete dct[key]. dct is modified in-place.

    If default is given, return it if dct[key] doesn't exist, otherwise raise
    KeyError.  """

    try:
        val = dct[key]
    except KeyError:
        if default is NotGiven:
            raise
        else:
            return default
    else:
        del dct[key]
        return val
#----------------------------------------------------------------------------


----------------------------------------------------------------------

Comment By: Michael Stone (mbrierst)
Date: 2003-02-26 16:54

Message:
Logged In: YES 
user_id=670441

I'm not sure how "compelling" people will find it, but 
I submitted patch 693753 to implement this behavior.
If it is not desired, this bug should probably be closed.


----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2002-11-18 23:17

Message:
Logged In: YES 
user_id=21627

No need to worry. If somebody gets it done before, they will
just close this report, so you'll know its done. Otherwise,
we can leave it open nearly indefinitely - we are all
insanely busy, all the time :-)

----------------------------------------------------------------------

Comment By: Fernando Pérez (fer_perez)
Date: 2002-11-18 19:35

Message:
Logged In: YES 
user_id=395388

Martin, I'd love to give it a go, but right now I'm insanely busy (I shouldn't even be worrying about this :)

In about two weeks things will calm down a bit though, and I could look into it. But I don't know the interpreter core at all, so I'd probably need a bit of guidance as to what files to look at (I don't want to spend an afternoon grepping).

And  I know very little about the python interenals (for example, about how to handle python exceptions from the C side). But with a bit of guidance I can manage. So if nobody else who knows the system well and can do it in 10 minutes is interested, and if someone is willing to point me in the right direction, I can look into it two/three weeks from now.

----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2002-11-18 12:17

Message:
Logged In: YES 
user_id=21627

Fernando, I sympathize with this request in principle,
although I'm concerned about the ever-growing complexity of
dictionary methods.

Would you be interested in implementing an actual patch to
provide this feature?

----------------------------------------------------------------------

Comment By: Fernando Pérez (fer_perez)
Date: 2002-11-18 09:47

Message:
Logged In: YES 
user_id=395388

This is a repost of my reply in c.l.py, for reference here. Alex Martelli just posted a detailed reply to c.l.py, roughly along the lines of mine (with more specific arguments and code examples).

Raymond Hettinger wrote:

> Do you have use cases demonstrating the value of a default rather than an
> exception?

Sure. First, on principle: the exception option is still there, if no default is provided. What giving a default buys you is not having to trap the exception yourself. If you want a missing key to generate an exception, simply don't give a default and that's it. Since it doesn't change the existing semantics (the current form doesn't take any arguments, so there can't be any confusion), I think it's a good addition.

But you asked for code. Here's an example from a wrapper which needs to filter out a keyword dictionary given to a function before passing it downstream. It needs to remove keywords which won't be understood by the downstream function, but it knows how to make a default decision if the keyword wasn't given:

        # Filter out other options the original plot doesn't know
        hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
        titles = popkey(keyw,'titles',0)

This uses my popkey() function, with the new method it would be simply

        # Filter out other options the original plot doesn't know
        hardcopy = keyw.pop('hardcopy',psargs['filename'] is not None)
        titles = keyw.pop('titles',0)

if my suggestion were accepted. I can always live with my popkey() function instead, if the crippled version is left in the language :) What I won't do is use the crippled pop() and wrap things everywhere with explicit try/except blocks. In the end that only hurts readaility and creates bloat.

This is part of the Gnuplot wrappers in IPython, if you want to see the full code (or I can give more context). IPython lives at 
http://www-hep.colorado.edu/~fperez/ipython

> Also, discuss why similarity with dict.get() applies instead of symmetry
> with list.pop() or dict.popitem().

- list.pop: I wasn't looking when that was written :) But I could argue similarly that an optional default argument would be a sensible, useful addition. No semantic break for existing code, and it saves people setting up try/except traps.

- dict.popitem: this one I'm ok with not having a default value, since it is meant to traverse the dict in essentially random order. Adding a default value would be like having a dict_with_default kind of object, which is definitely different from a regular python dict. popitem() returns a k/v pair and is typically used for exhausting a dict destructively, so it makes a lot of sense to break at the end. 

But pop(key) is much more specific, so I think it is sensible to be able to control its behavior more closely. Just like dict.get(), which allows straight through the function interface one to control what happens to missing keys. Semantically pop(key) is almost like get(key), with the difference that it deletes the k/v entry from the dict. It seems only natural then that pop() would support the same default arg behavior that get() has.

Cheers,

f.

----------------------------------------------------------------------

Comment By: Raymond Hettinger (rhettinger)
Date: 2002-11-18 08:02

Message:
Logged In: YES 
user_id=80475

dict.pop(k) parallels list.remove(elem), dict.popitem(), and 
list.pop([i]) which all raise exceptions instead of returning 
a default.

Do you have compelling use cases?

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=639806&group_id=5470