[Python-ideas] Override dict.__new__ to raise if cls is not dict; do the same for str, list, etc.

Chris Angelico rosuav at gmail.com
Thu Apr 21 01:14:29 EDT 2016


On Thu, Apr 21, 2016 at 2:33 PM, Neil Girdhar <mistersheik at gmail.com> wrote:
> I think inheriting directly from dict is simply bad code because CPython
> doesn't promise that any of your overridden methods will be called.  The
> fact that it silently doesn't call them is an inscrutable trap.  And really,
> it's not much of a "punishment" to simply change your base class name.

There are way too many cases that work just fine, though.

>>> class AutoCreateDict(dict):
...     def __missing__(self, key):
...         return "<autocreated %r>" % key
...
>>> acd = AutoCreateDict()
>>> acd["asdf"]
"<autocreated 'asdf'>"

Why should I inherit from UserDict instead? I have to import that from
somewhere (is it in types? collections? though presumably your error
message would tell me that), and then I have to contend with the fact
that my class is no longer a dictionary.

>>> class AutoCreateUserDict(collections.UserDict):
...     def __missing__(self, key):
...         return "<autocreated %r>" % key
...
>>> acud = AutoCreateUserDict()
>>> acud["qwer"]
"<autocreated 'qwer'>"
>>> json.dumps(acd)
'{}'
>>> json.dumps(acud)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'AutoCreateUserDict' is not JSON serializable

If you *do* push forward with this proposal, incidentally, I would
recommend not doing it in __new__, but changing it so the class is no
longer subclassable, as per bool:

>>> class X(int): pass
...
>>> class X(bool): pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type 'bool' is not an acceptable base type

But I am firmly -1 on disallowing dict subclasses just because they
aren't guaranteed to call all of your overridden methods.

ChrisA


More information about the Python-ideas mailing list