__slots__ vs __dict__

Marcus von Appen mva at sysfault.org
Thu May 13 12:20:14 EDT 2004


Andrew Bennetts <andrew-pythonlist at puzzling.org> writes:

[...]

> Now your example runs just fine (i.e. the script terminates normally, and
> nothing happens).  I still don't see any error. 

I thought you would inspect the objects yourself. Let me show you another (now
working)  example, which will explain it:

------
class DictClass (object):
    test = "DictTest"

    def __init__ (self):
        pass

class SlotClass (object):
    __slots__ = "test"

    def __init__ (self):
        self.test = "SlotTest"

def print_obj (obj):
    # inspect .test and show the object attributes
    print obj.test
    print dir (obj)

    # bind new attribute and inspect the object attributes
    obj.new_test = "Test"
    print obj.new_test
    print dir (obj)
    print "------"
    return

if __name__ == "__main__":
    dict_obj = DictClass ()
    slot_obj = SlotClass ()

    print_obj (dict_obj)
    print_obj (slot_obj)

---

You will get something like the following output:

----------------
DictTest
['__class__', '__delattr__', '__dict__', .....,  '__weakref__', 'test']

Test
['__class__', '__delattr__', '__dict__', ...., '__weakref__', 'new_test',
 'test']

------

SlotTest
['__class__', '__delattr__', ....,  '__slots__', '__str__', 'test']

Traceback (most recent call last):
  File "foo.py", line 31, in ?
    print_obj (slot_obj)
  File "foo.py", line 19, in print_obj
    obj.new_test = "Test"
AttributeError: 'SlotClass' object has no attribute 'new_test'
----------------

As you will notice, a __slot__ed object/class has no __weakref__ nor __dict__
attribute.
Thus binding new object attributes will fail with an AttributeError.

So let's try it again with using __setattr__ in SlotClass:

class SlotClass (object):
    test = "SlotTest"
    test2 = "SlotTest2" # just for making a tuple creation easier
    __slots__ = test, test2

    def __init__ (self):
        pass
    
    def __setattr__ (self, name, value):
        # create a dict here to add its key to the __slot__ tuple
        self.__slots__.__add__ (tuple ((name)))
        return

    
def print_obj (obj):
    # inspect .test and show the object attributes
    print obj.test
    print dir (obj)

    # bind new attribute and inspect the object attributes
    obj.new_test = "Test"
    print obj.new_test
    print dir (obj)
    print "------"
    return

if __name__ == "__main__":

    #dict_obj = DictClass ()
    slot_obj = SlotClass ()

    #print_obj (dict_obj)
    print_obj (slot_obj)

----


As you will see, you get an AttributeError again.tuple ((name))was not 
concatenated to __slots__.
I think that should explain enough about the advantage and disadvantage of 
__slots__ here.

 (And why do you keep
> putting a redundant return at the end of your functions?)

I'm used to it :-).

> Are you sure this is the same code that you get a crash with?  What version
> of Python are you using? (I've tested with 2.2.3 and 2.3.3).

No, I put messy code without _really_ thinking about it in my first post.
I did not realize that self.__slots__ = self._slots in __setattr__ will end
up in a recursion...

Regards
Marcus

-- 
We don't understand the software, and sometimes we don't understand the 
hardware, but we can *see* the blinking lights!



More information about the Python-list mailing list