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

Ethan Furman ethan at stoneleaf.us
Fri Apr 22 07:51:47 EDT 2016


On 04/21/2016 11:06 PM, Chris Angelico wrote:
> On Fri, Apr 22, 2016 at 3:17 PM, Ben Finney wrote:
>> Random832 writes:

>>> Because looking up an attribute implies getting an item from the
>>> object or class's __dict__ with a string key of the name of the
>>> attribute (see below for the documented basis for this assumption).
>>
>> No, that's not what it implies. The ‘__dict__’ of an object is an
>> implementation detail, and is not necessarily used for attribute lookup.
>>
>> As the documentation says:
>>
>>      A class has a namespace implemented by a dictionary object. Class
>>      attribute references are translated to lookups in this dictionary,
>>      e.g., C.x is translated to C.__dict__["x"] (although there are a
>>      number of hooks which allow for other means of locating attributes).
>>
>>      <URL:https://docs.python.org/3.5/reference/datamodel.html>
>
> Okay. That definitely implies that the class itself has a real dict,
> though.

A class does have a real dict() -- not a subclass, not a look-a-like, 
but a real, honest-to-goodness, freshly minted {}.

> And it should be possible, using a metaclass, to manipulate
> that, right?

Only for the purposes of class creation.  One of the final steps of 
creating a class (after __prepare__ and __new__ have been called) is to 
copy everything from whatever dict (sub)class you used into a brand-new 
dict.

> Maybe I'm just misunderstanding how metaclasses should be written, but
> this seems like it ought to work.

You have the metaclass portion right.

> And it's not making any use of the
> AutoCreateDict - despite __prepare__ and __new__ clearly being called,
> the latter with an AutoCreateDict instance.

Well, it would if you tried creating any attributes without values 
during class creation.

> But by the time it gets
> actually attached to the dictionary, we have a mappingproxy that
> ignores __missing__.

No, it's a dict -- we just don't get to directly fiddle with it (hence 
the return of a mappingproxy).

> The docs say "are translated to", implying that
> this will actually be equivalent.

> Is there any way to make use of this documented transformation?

There are already many hooks in place to supplement or replace attribute 
lookup -- use them instead.  :)

--
~Ethan~



More information about the Python-ideas mailing list