[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 22:13:00 EDT 2016


On Fri, Apr 22, 2016 at 12:00 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Thu, Apr 21, 2016 at 09:43:17AM -0400, Random832 wrote:
>> On Thu, Apr 21, 2016, at 07:17, Steven D'Aprano wrote:
>> > and it runs counter to a documented feature of dicts, that they can be
>> > subclassed and given a __missing__ method:
>> >
>> > "If a SUBCLASS OF DICT [emphasis added] defines a method __missing__()
>> > and key is not present, the d[key] operation calls that method ..."
>>
>> So what method should be overridden to make a dict subclass useful as a
>> class or object dictionary (i.e. for attribute lookup to work with names
>> that have not been stored with dict.__setitem__)?
>
> I don't understand your question. Or rather, if I have understood it,
> the question has a trivial answer: you don't have to override anything.
>
> class MyDict(dict):
>     pass
>
> d = MyDict()
> d.attr = 1
> print(d.attr)
>
>
> will do what you appear to be asking. If that's not what you actually
> mean, then you need to explain more carefully.

"As a class or object dictionary". Consider:

>>> class X: pass
...
>>> X().__dict__
{}
>>> type(_)
<class 'dict'>

Now, what can I replace that with? A regular dict works fine:

>>> x = X()
>>> x.__dict__ = {"asdf": 1}
>>> x.asdf
1

But defining __missing__ doesn't create attributes automatically:

>>> class AutoCreateDict(dict):
...     def __missing__(self, key):
...         return "<%r>" % key
...
>>> x.__dict__ = AutoCreateDict()
>>> x.qwer
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'qwer'

And neither does overriding __getitem__:

>>> class OtherAutoCreateDict(dict):
...     def __getitem__(self, key):
...         try: return super().__getitem__(key)
...         except KeyError: return "<%r>" % key
...
>>> x.__dict__ = OtherAutoCreateDict()
>>> x.zxcv
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'zxcv'

The question is a fair one. What can you do to make an object's
dictionary provide attributes that weren't put there with __setitem__?

ChrisA


More information about the Python-ideas mailing list