__delitem__ "feature"

K

kj

When I execute this file:

#----------------------------------------------------------------------
def nodelfactory(klass):
class nodel(klass):
def _delitem(self, _):
raise TypeError("can't delete")

# __delitem__ = _delitem

def __init__(self, *a, **k):
klass.__init__(self, *a, **k)
self.__delitem__ = self._delitem

nodel.__name__ = 'nodel%s' % klass.__name__
return nodel


if __name__ == '__main__':
import traceback as tb


d = nodelfactory(dict)([('k1', 'v1'), ('k2', 'v2')])

try: d.__delitem__('k1')
except TypeError: tb.print_exc()
print d

try: del d['k1']
except TypeError: tb.print_exc()
print d


l = nodelfactory(list)([1, 2, 3, 4])

try: l.__delitem__(0)
except TypeError: tb.print_exc()
print l

try: del l[0]
except TypeError: tb.print_exc()
print l
#----------------------------------------------------------------------

....the output I get is:

Traceback (most recent call last):
File "/tmp/delbug.py", line 20, in <module>
try: d.__delitem__('k1')
File "/tmp/delbug.py", line 4, in _delitem
raise TypeError("can't delete")
TypeError: can't delete
{'k2': 'v2', 'k1': 'v1'}
{'k2': 'v2'}
Traceback (most recent call last):
File "/tmp/delbug.py", line 30, in <module>
try: l.__delitem__(0)
File "/tmp/delbug.py", line 4, in _delitem
raise TypeError("can't delete")
TypeError: can't delete
[1, 2, 3, 4]
[2, 3, 4]

It means that, for both subclasses, del fails to trigger the
dynamically installed instance method __delitem__.

If I replace dict with UserDict, *both* deletion attempts lead to
a call to the dynamic __delitem__ method, and are thus blocked.
This is the behavior I expected of dict (and will help me hold on
to my belief that I'm not going insane when inevitably I'm told
that there's no bug in dict or list).

Interestingly enough, if I replace list with UserList, I see no
change in behavior. So maybe I am going insane after all.

~kj

P.S. If you uncomment the commented-out line, and comment out the
last line of the __init__ method (which installs self._delitem as
self.__delitem__) then *all* the deletion attempts invoke the
__delitem__ method, and are therefore blocked. FWIW.
 
I

Ian Kelly

P.S. If you uncomment the commented-out line, and comment out the
last line of the __init__ method (which installs self._delitem as
self.__delitem__) then *all* the deletion attempts invoke the
__delitem__ method, and are therefore blocked. FWIW.

Because subclasses of builtins only check the class __dict__ for special
method overrides, not the instance __dict__.
 
K

kj

Because subclasses of builtins only check the class __dict__ for special
method overrides, not the instance __dict__.


How do you know this? Is this documented? Or is this a case of
Monday-night quarterbacking?

~kj
 
S

Steven D'Aprano

In <[email protected]> Ian Kelly




How do you know this? Is this documented? Or is this a case of
Monday-night quarterbacking?

We know it because it explains the observable facts.

It also happens to be documented, but documentation can be wrong or
incomplete. The facts are never wrong, since by definition they are the
facts.
 
I

Ian Kelly

How do you know this?

From memory, although it seems I remembered it slightly wrong; it's the
way new-style classes work in general, not anything to do with builtins
in particular.
Is this documented?

Yes, as others have pointed out.
Or is this a case of Monday-night quarterbacking?

Do you mean "Monday-morning quarterbacking"? Either way, I don't know
what you mean by that in this context.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top