Say I have a class which defines __slots__
:
class Foo(object):
__slots__ = ['x']
def __init__(self, x=1):
self.x = x
# will the following work?
def __setattr__(self, key, value):
if key == 'x':
object.__setattr__(self, name, -value) # Haha - let's set to minus x
Can I define __setattr__()
for it?
Since Foo
has no __dict__
, what will it update?
All your code does, apart from negate the value, is call the parent class __setattr__
, which is exactly what would happen without your __setattr__
method. So the short answer is: Sure you can define a __setattr__
.
What you cannot do is redefine __setattr__
to use self.__dict__
, because instances of a class with slots do not have a __dict__
attribute. But such instances do have a self.x
attribute, it's contents are just not stored in a dictionary on the instance.
Instead, slot values are stored in the same location a __dict__
instance dictionary would otherwise be stored; on the object heap. Space is reserved for len(__slots__)
references, and descriptors on the class access these references on your behalf.
So, in a __setattr__
hook, you can just call those descriptors directly instead:
def __setattr__(self, key, value):
if key == 'x':
Foo.__dict__[key].__set__(self, -value)
Interesting detour: yes, on classes without a __slots__
attribute, there is a descriptor that would give you access to the __dict__
object of instances:
>>> class Bar(object): pass
...
>>> Bar.__dict__['__dict__']
<attribute '__dict__' of 'Bar' objects>
>>> Bar.__dict__['__dict__'].__get__(Bar(), Bar)
{}
which is how normal instances can look up self.__dict__
. Which makes you wonder where the Bar.__dict__
object is found. In Python, it is turtles all the way down, you'd look that object up on the type
object of course:
>>> type.__dict__['__dict__']
<attribute '__dict__' of 'type' objects>
>>> type.__dict__['__dict__'].__get__(Bar, type)
dict_proxy({'__dict__': <attribute '__dict__' of 'Bar' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None})