Setdefault bypasses __setitem__

Discussion in 'Python' started by Ron Garret, Oct 13, 2005.

  1. Ron Garret

    Ron Garret Guest

    Is this a bug or a feature?

    class mydict(dict):
    def __setitem__(self, key, val):
    print 'foo'
    dict.__setitem__(self, key, val)

    >>> d=mydict()
    >>> d[1]=2

    foo
    >>> d.setdefault(2,3)

    3

    rg
    Ron Garret, Oct 13, 2005
    #1
    1. Advertising

  2. Ron Garret wrote:
    > Is this a bug or a feature?
    >
    > class mydict(dict):
    > def __setitem__(self, key, val):
    > print 'foo'
    > dict.__setitem__(self, key, val)
    >
    >
    >>>>d=mydict()
    >>>>d[1]=2

    >
    > foo
    >
    >>>>d.setdefault(2,3)



    Feature. If it wouldn't bypass __setitem__, how exactly would you make a
    default-item? Using __setitem__ implies a key. So if setdefault
    was implemented as

    def setdefault(self, v):
    self["SOME_DEFAULT_KEY_NAME"] = v

    and later on one writes e.g. a HTML-page with a form input field named
    "SOME_DEFAULT_KEY_NAME" that gets stored in a dict - it would overwrite
    the default value.

    So it has to bypass __setitem__, as otherwise it can't distinguish
    between "real" and the default value - the latter one is not allowed to
    have a key that is in any imaginable way used by the user.

    Diez
    Diez B. Roggisch, Oct 13, 2005
    #2
    1. Advertising

  3. Ron Garret

    Peter Otten Guest

    Diez B. Roggisch wrote:

    > Ron Garret wrote:
    >> Is this a bug or a feature?
    >>
    >> class mydict(dict):
    >> def __setitem__(self, key, val):
    >> print 'foo'
    >> dict.__setitem__(self, key, val)
    >>
    >>
    >>>>>d=mydict()
    >>>>>d[1]=2

    >>
    >> foo
    >>
    >>>>>d.setdefault(2,3)

    >
    >
    > Feature. If it wouldn't bypass __setitem__, how exactly would you make a
    > default-item? Using __setitem__ implies a key. So if setdefault
    > was implemented as
    >
    > def setdefault(self, v):
    > self["SOME_DEFAULT_KEY_NAME"] = v
    >
    > and later on one writes e.g. a HTML-page with a form input field named
    > "SOME_DEFAULT_KEY_NAME" that gets stored in a dict - it would overwrite
    > the default value.
    >
    > So it has to bypass __setitem__, as otherwise it can't distinguish
    > between "real" and the default value - the latter one is not allowed to
    > have a key that is in any imaginable way used by the user.


    The implementation is certainly a design decision. setdefault() could be
    implemented in terms of __set/getitem__() as

    def setdefault(self, key, value=None):
    try:
    return self[key]
    except KeyError:
    self[key] = value
    return self[key]

    I guess it's not done for performance reasons.

    Peter
    Peter Otten, Oct 13, 2005
    #3
  4. > The implementation is certainly a design decision. setdefault() could be
    > implemented in terms of __set/getitem__() as
    >
    > def setdefault(self, key, value=None):
    > try:
    > return self[key]
    > except KeyError:
    > self[key] = value
    > return self[key]
    >
    > I guess it's not done for performance reasons.


    Nope. What if you changed your default value? Then you'd have to update
    the whole dictionary - but without keeping track of the keys you placed
    the default value under that isn't possible. Which strikes me as
    more-than-marginal overhead - without any advantage (as using
    __setitem__ for the default value isn't something I consider being a
    missing feature...)

    Diez
    Diez B. Roggisch, Oct 13, 2005
    #4
  5. Ron Garret

    Peter Otten Guest

    Diez B. Roggisch wrote:

    >> The implementation is certainly a design decision. setdefault() could be
    >> implemented in terms of __set/getitem__() as
    >>
    >> def setdefault(self, key, value=None):
    >> try:
    >> return self[key]
    >> except KeyError:
    >> self[key] = value
    >> return self[key]
    >>
    >> I guess it's not done for performance reasons.

    >
    > Nope. What if you changed your default value? Then you'd have to update
    > the whole dictionary - but without keeping track of the keys you placed
    > the default value under that isn't possible. Which strikes me as
    > more-than-marginal overhead - without any advantage (as using
    > __setitem__ for the default value isn't something I consider being a
    > missing feature...)


    Are we talking about the same setdefault()?

    setdefault(...)
    D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D

    There is no per-instance default value just on per call:

    >>> d = {}
    >>> d.setdefault("a", 1)

    1
    >>> d.setdefault("a", 42)

    1

    I'm sure there is a misunderstanding in our conversation, I'm just not able
    to nail it...

    Peter
    Peter Otten, Oct 13, 2005
    #5
  6. Peter Otten wrote:

    > Are we talking about the same setdefault()?
    >
    > setdefault(...)
    > D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D


    note that it might be spelled "setdefault", but it should be pronounced
    "get or set".

    </F>
    Fredrik Lundh, Oct 13, 2005
    #6
  7. Ron Garret

    Duncan Booth Guest

    Diez B. Roggisch wrote:

    > So if setdefault
    > was implemented as
    >
    > def setdefault(self, v):
    > self["SOME_DEFAULT_KEY_NAME"] = v


    if setdefault was implemented that way then all current uses of setdefault
    would throw an exception.

    setdefault takes *three* parameters: self, key, value. Once you include the
    key parameter your entire argument implodes.
    Duncan Booth, Oct 13, 2005
    #7

  8. > Are we talking about the same setdefault()?
    >
    >
    > D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
    >
    > There is no per-instance default value just on per call:


    Oh. You're right. I was somehow under the impression that setdefault is
    per-instance, so that I can avoid

    d.get(key, default)

    and write

    d[key]

    instead, for all keys, and get no more KeyErrors. But then you are
    right of course.

    Regards,

    Diez
    Diez B. Roggisch, Oct 13, 2005
    #8
  9. Duncan Booth wrote:
    > Diez B. Roggisch wrote:
    >
    >
    >>So if setdefault
    >>was implemented as
    >>
    >>def setdefault(self, v):
    >> self["SOME_DEFAULT_KEY_NAME"] = v

    >
    >
    > if setdefault was implemented that way then all current uses of setdefault
    > would throw an exception.
    >
    > setdefault takes *three* parameters: self, key, value. Once you include the
    > key parameter your entire argument implodes.


    Yup. It does implode, leaving me thunderstruck because of my dumbness.

    I rarely find things in python strange or named incorrectly, but this is
    IMHO such a case - setdefault led me to think that using it would set a
    default value to return for _future_ lookups of non-existant keys. That
    semantics is known in e.g. ruby or java.

    I think a better name would be getdefault, or even get_setdefault - in
    oppposition to the get(key, d) form.

    But now that this became clear to me... I guess I can live with the name :)

    Diez
    Diez B. Roggisch, Oct 14, 2005
    #9
  10. Diez B. Roggisch wrote:

    > I rarely find things in python strange or named incorrectly, but this is
    > IMHO such a case - setdefault led me to think that using it would set a
    > default value to return for _future_ lookups of non-existant keys. That
    > semantics is known in e.g. ruby or java.
    >
    > I think a better name would be getdefault, or even get_setdefault - in
    > oppposition to the get(key, d) form.
    >
    > But now that this became clear to me... I guess I can live with the name :)


    as long as you pronounce it correctly (see my earlier post).

    </F>
    Fredrik Lundh, Oct 14, 2005
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tino Lange

    <dict>.setdefault()

    Tino Lange, Jul 31, 2003, in forum: Python
    Replies:
    5
    Views:
    401
    Steven Taschuk
    Aug 1, 2003
  2. Leo Breebaart

    Delayed evaluation and setdefault()

    Leo Breebaart, Jan 19, 2004, in forum: Python
    Replies:
    7
    Views:
    429
  3. Cole Tuininga

    setdefault threadsafe?

    Cole Tuininga, Aug 24, 2004, in forum: Python
    Replies:
    0
    Views:
    368
    Cole Tuininga
    Aug 24, 2004
  4. gyan
    Replies:
    7
    Views:
    975
    Victor Bazarov
    May 19, 2006
  5. MisterPete
    Replies:
    4
    Views:
    296
    MisterPete
    May 30, 2007
Loading...

Share This Page