Setdefault bypasses __setitem__

D

Diez B. Roggisch

Ron said:
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
 
P

Peter Otten

Diez said:
Ron said:
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
 
D

Diez B. Roggisch

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
 
P

Peter Otten

Diez said:
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:
1

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

Peter
 
F

Fredrik Lundh

Peter said:
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>
 
D

Duncan Booth

Diez said:
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.
 
D

Diez B. Roggisch

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
 
D

Diez B. Roggisch

Duncan said:
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
 
F

Fredrik Lundh

Diez said:
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>
 

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
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top