25

The __dict__ of a type is a dictproxy object that is read only. I want to know what's the purpose of it. Is it only for "don't allow modify builtin types"? I found a method that can walk around this. I know it's not a good idea to modify builtin types. But I am trying to modify cdef class of Cython on fly.

I want to know are there any dangerous to modify the __dict__ of cdef class this way?

Here is the code:

import gc
gc.get_referents(float.__dict__)[0]["square"] = lambda self: self*self
(3.14).square()
HYRY
  • 94,853
  • 25
  • 187
  • 187
  • 1
    Probably [THIS LINK](http://legacy.python.org/dev/peps/pep-0232/) and [THIS LINK](http://stackoverflow.com/questions/7439023/why-do-python-functions-have-a-dict) will help – Tanmaya Meher Aug 22 '14 at 06:23
  • possible duplicate of [modify class \_\_dict\_\_ (mappingproxy) in python](http://stackoverflow.com/questions/20019333/modify-class-dict-mappingproxy-in-python) – mtvec Aug 22 '14 at 07:23
  • @Job, It's not the same question, becasue `setattr` doesn't work for builtin class. What I want to do is modify the `__dict__` of `cdef class` of Cython. – HYRY Aug 22 '14 at 08:02
  • 1
    Your example modifies `float` for all sub-interpreters running in the same process. Also, by bypassing `type_setattro`, it doesn't sync with the `PyTypeObject` slot for a special method (`update_slot`) or clear the method cache (`PyType_Modified`). I don't know about a `cdef class`, but the Python 3 stable API has `PyType_FromSpec` to create an extension heap type that can be modified safely by setting attributes normally instead of hacking the class dict. – Eryk Sun Nov 10 '14 at 16:16
  • `_tkinter.Tcl_Obj` is an example Python 3 extension type that lets you set attributes. – Eryk Sun Nov 10 '14 at 16:22

2 Answers2

19

The purpose of dictproxy (found in classes) is to allow for optimisations in the Python interpreter and to ensure its stability. See MartijnPieters comment below for details on the requirements for the optimisations, which apparently rely on the keys of class.__dict__ always being strings.

dictproxy also seems to play a role in protecting against certain instabilities in the interpreter. For more information on one such instability, see the bug report and bug fix discussed on python.org with the title Bypassing __dict__ readonlyness. If you don't use some kind of proxy mechanism, then the __dict__ can be written to. If it can be written, it can be deleted. In the bug report they discuss some scenarios in which the __dict__ could be deleted and caused the interpreter to crash.

Note that this contrasts with class instances, which you can assign to directly or with __setitem__():

  • instance.__dict__['x'] = 1

Also, the instance __dict__ can be deleted. If it is deleted, then it gets automatically re-created when attribute assignment is attempted:

del instance.__dict__ instance.a = 1 instance.__dict__

Conclusion

So in sum, dictproxy allows classes to operate more optimally and makes the interpreter more stable.

Scott H
  • 2,644
  • 1
  • 24
  • 28
  • 3
    The `dictproxy` is used to ensure that the keys in a `class.__dict__` are always strings, allowing for a number of optimisations in the Python interpreter. The proxy prevents writing to `class.__dict__`, so only `setattr()` can be used, and the `class.__setattr__` implementation enforces the keys-must-be-strings limitation. – Martijn Pieters Sep 22 '15 at 15:34
7

__dict__ is a namespace object that holds the class' attributes.

There shouldn't be a problem modifying the dict object as long as you don't modify the __dict__ itself:

Example:

//good
MyClass.x = 1 

//bad
MyClass.__dict__['x'] = 1

//good
m = MyClass()
m.x = 1

//also good
m.__dict__['x'] = 1

Python documentation [ LINK ]: Attribute assignment updates the module’s namespace dictionary, e.g., m.x = 1 is equivalent to m.__dict__["x"] = 1.

so there should be no problem modifying objects of the dict.

Furthermore:

Since we can modify the attributes of a class the dict of a class is always Writable:

__dict__ | The namespace supporting arbitrary function attributes. | Writable

Note

It could be CPython has a slightly different implementation than Python, but as I can read from the documentation it's not mentioned.

Wouter
  • 534
  • 3
  • 14
  • 22
Persijn
  • 14,624
  • 3
  • 43
  • 72