[Python-Dev] Evil setattr hack
Guido van Rossum
guido@python.org
Mon, 14 Apr 2003 20:35:34 -0400
> Someone accidentally discovered a way to set attributes of built-in
> types, even though the implementation tries to prevent this.
I've checked in what I believe is an adequate block for at least this
particular hack. wrap_setattr(), which is called in response to
<type>.__setattr__(), now compares if the C function it is about to
call is the same as the C function in the built-in base class closest
to the object's class. This means that if B is a built-in class and P
is a Python class derived from B, P.__setattr__ can call
B.__setattr__, but not A.__setattr__ where A is an (also built-in)
base class of B (unless B inherits A.__setattr__).
The following session shows that object.__setattr__ can no longer be
used to set a type's attributes:
Remind us that 'str' is an instance of 'type':
>>> isinstance(str, type)
True
'type' has a __setattr__ method that forbids setting all attributes.
Try type.__setattr__; nothing new here:
>>> type.__setattr__(str, "foo", 42)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: can't set attributes of built-in/extension type 'str'
Remind us that 'object' is a base class of 'type':
>>> issubclass(type, object)
True
Now try object.__setattr__. This used to work; now it shows the new
error message:
>>> object.__setattr__(str, "foo", 42)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: can't apply this __setattr__ to type object
__delattr__ has the same restriction, or else you would be able to
remove existing str methods -- not good:
>>> object.__delattr__(str, "foo")
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: can't apply this __delattr__ to type object
In other (normal) circumstances object.__setattr__ still works:
>>> class C(object):
... pass
...
>>> x = C()
>>> object.__setattr__(x, "foo", 42)
>>> object.__delattr__(x, "foo")
I'll backport this to Python 2.2 as well.
--Guido van Rossum (home page: http://www.python.org/~guido/)