On Monday, July 4, 2016 at 12:02:41 AM UTC+8, Steven D'Aprano wrote: > I have some code which can preprocess (using a metaclass) or postprocess > (using a decorator) a class: > > @process > class K: > pass > > > class K(metaclass=process): > pass > > > Both should give the same result, but I have found that the results are > slightly different because the dict passed to process as a metaclass is > different from the the class dict seen by the decorator. I can demonstrate > the difference in Python 3.6 by using this metaclass/decorator: > > class process(type): > def __new__(meta, *args): > if len(args) == 1: > # decorator usage > cls = args[0] > d = cls.__dict__ > elif len(args) == 3: > # metaclass usage > name, bases, d = args > cls = super().__new__(meta, *args) > print(sorted(d.keys())) > return cls > > > If I then try it against two identical (apart from their names) classes, I > get these results: > > > py> @process > ... class K: > ... x = 1 > ... > ['__dict__', '__doc__', '__module__', '__weakref__', 'x'] > py> class Q(metaclass=process): > ... x = 1 > ... > ['__module__', '__qualname__', 'x'] > > > > Now if I check the newly created Q, I see the same keys K has: > > py> sorted(Q.__dict__.keys()) > ['__dict__', '__doc__', '__module__', '__weakref__', 'x'] > > > Is there any documentation for exactly what keys are added to classes when? > > > > > -- > Steven > “Cheer up,” they said, “things could be worse.” So I cheered up, and sure > enough, things got worse.
eryk sun has a very good explanation. I want to add two points: 1. __qualname__ though passed in class creation, but it won't appear in the class.__dict__ since it is deliberately deleted from __dict__ in type_new. 2. __dict__ and __weakref__ are possible to be added even when there is not __slots__. __dict__ can be added when the base class's dictoffset == 0 and __weakref__ can be added when the base class's weakrefoffset == 0 && tp_itemsize == 0. An example is: In [2]: class T(int): ...: pass ...: In [3]: T.__dict__ Out[3]: mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'T' objects>, '__doc__': None}) I think this is a nice design in attribute searching. BTW, I think this is a implementation detail. If you rely on it, it may easily break in the future. -- https://mail.python.org/mailman/listinfo/python-list