homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: The result of calling dict.* methods on OrderedDict is undefined.
Type: behavior Stage:
Components: Documentation Versions: Python 3.6, Python 3.4, Python 3.5, Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: Mark.Shannon, docs@python, eric.snow, rhettinger
Priority: low Keywords:

Created on 2015年07月25日 17:10 by eric.snow, last changed 2022年04月11日 14:58 by admin. This issue is now closed.

Messages (5)
msg247354 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2015年07月25日 17:10
(see issue24667)
collections.OrderedDict subclasses dict so calling dict's methods on an OrderedDict works. However, neither the pure Python nor the C implementation of OrderedDict was written to support doing so. In fact, both of them currently enter an inconsistent state when this happens. For example:
 # Python 3.4 (pure Python implementation)
 >>> from collections import OrderedDict
 >>> od = OrderedDict([('spam', 1), ('eggs', 2)])
 >>> dict.__delitem__(od, 'spam')
 >>> str(od)
 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "/usr/lib/python3.4/reprlib.py", line 24, in wrapper
 result = user_function(self)
 File "/usr/lib/python3.4/collections/__init__.py", line 198, in __repr__
 return '%s(%r)' % (self.__class__.__name__, list(self.items()))
 File "/usr/lib/python3.4/_collections_abc.py", line 485, in __iter__
 yield (key, self._mapping[key])
 KeyError: 'spam'
 # Python 3.5 (C implementation)
 >>> from collections import OrderedDict
 >>> od = OrderedDict([('spam', 1), ('eggs', 2)])
 >>> dict.__delitem__(od, 'spam')
 >>> str(od)
 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 KeyError: 'spam'
This is a consequence of subclassing a builtin type, which typically do not have good support for subclassing (e.g. issue10977).
It probably isn't worth making any changes to the code of either OrderedDict implementations. At most I'd recommend a note in the OrderedDict documentation indicating that the results of passing an OrderedDict object to dict.* methods are undefined.
msg247358 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015年07月25日 17:31
> This is a consequence of subclassing a builtin type
Not really. This is how subclassing works in general. Any time you a user calls a parent class directly on an instance of subclass, they are bypassing whatever the subclass needs to do to maintain its invariants.
class A:
 def __init__(self):
 self.data = []
 def add(self, x):
 self.data.append(x)
class B(A):
 'Track the number of odds'
 def __init__(self):
 A.__init__(self)
 self.odds = 0
 def add(self, x):
 A.add(self, x)
 self.odds += (x % 2)
b = B()
b.add(1)
b.add(2)
b.add(3)
b.add(4)
A.add(b, 5)
assert b.odds == sum(x%1 for x in b.data), 'OMG, B is broken!'
There is nothing special about OrderedDicts in this regard. Perhaps there should be a FAQ entry regarding the "facts of life" in the world of object oriented programming.
msg247360 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2015年07月25日 17:40
Ah, you're right. I was hung up on issue10977. :)
msg247361 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2015年07月25日 17:50
Feel free to close this, Raymond.
msg247423 - (view) Author: Mark Shannon (Mark.Shannon) * (Python committer) Date: 2015年07月26日 10:41
I think this is a bug. This is not a normal case of subclassing as the interpreter calls the C API PyDict_XXX() in many cases where a dictionary subclass is passed in.
For example:
class C: pass
c = C()
# Liskov substitution principle says this is OK.
c.__dict__ = OrderedDict() 
c.a = 1
All access to the ordered dict is via the dict.__setitem__ method.
I think this should be documented.
History
Date User Action Args
2022年04月11日 14:58:19adminsetgithub: 68909
2015年07月26日 10:41:18Mark.Shannonsetnosy: + Mark.Shannon
messages: + msg247423
2015年07月25日 20:33:30rhettingersetstatus: open -> closed
resolution: not a bug
2015年07月25日 17:50:48eric.snowsetmessages: + msg247361
2015年07月25日 17:40:17eric.snowsetmessages: + msg247360
2015年07月25日 17:31:22rhettingersetmessages: + msg247358
2015年07月25日 17:12:08rhettingersetassignee: docs@python -> rhettinger
2015年07月25日 17:10:58eric.snowcreate

AltStyle によって変換されたページ (->オリジナル) /