[New-bugs-announce] [issue27411] Possible different behaviour of explicit and implicit __dict__ accessing when involving builtin types' __dict__ descriptors

Xiang Zhang report at bugs.python.org
Wed Jun 29 05:57:04 EDT 2016

New submission from Xiang Zhang:

Usually when we access an object's __dict__, it will finally reach 
subtype_dict[0]. When involving builtin base, it may delegates to the 
base's __dict__ descriptor. In such a case, it is possible for the 
__dict__ descriptor to initialize the dict object if it's NULL. This is
 what PyObject_GenericGetDict does. But if the __dict__ descriptor
initialize dict to other mapping objects instead of dict object, 
accessing __dict__ explicitly first or implicitly by attribute setting
 will result in different behaviours. If we first access obj.__dict__, 
obj.__dict__ will set to the mapping object, otherwise it will be set
 to a dict.

Let's make a example. For convenience I alter BaseException's __dict__
 descriptor, changing PyObject_GenericGetDict to custom_getdict:

PyObject *
custom_getdict(PyObject *obj, void *context)
    PyObject *dict, **dictptr = _PyObject_GetDictPtr(obj);
    dict = *dictptr;
    if (dict == NULL) {
        *dictptr = dict = PyDict_New();
        PyDict_SetItemString(dict, "test", PyDict_New());
    return dict;

And then the use case:

>>> BaseException().__dict__
{'test': {}}
>>> class A:
... 	pass
>>> class B(A, BaseException):
... 	def __init__(self):
... 	    self.__dict__['a'] = 1
...  	    self.b = 2
>>> class C(A, BaseException):
... 	def __init__(self):
...         self.a = 1   
...         self.__dict__['b'] = 2
>>> B().__dict__
{'b': 2, 'test': {}, 'a': 1}
>>> C().__dict__
{'a': 1, 'b': 2}

Since a and b are not descriptors, I think B().__dict__ and C().__dict__ should lead to same result but they are not. I think it's
because PyObject_GenericSetAttr doesn't go the same way as subtype_dict
so when it finds __dict__ is not initialized it always assign it a new

I am not sure this is a bug or a case worth fixing or is designed deliberately. BTW, subtype_dict was introduced in [1].
[0] https://hg.python.org/cpython/file/tip/Objects/typeobject.c#l2069
[1] http://bugs.python.org/issue1303614

components: Interpreter Core
messages: 269470
nosy: rhettinger, serhiy.storchaka, xiang.zhang
priority: normal
severity: normal
status: open
title: Possible different behaviour of explicit and implicit __dict__ accessing when involving builtin types' __dict__ descriptors
type: behavior
versions: Python 3.6

Python tracker <report at bugs.python.org>

More information about the New-bugs-announce mailing list