Question: I'm trying to understand slots. Therefore, I have written a little script with two classes, one using slots and one not. class A: def __init__(self, name): self.name = name def getName(self): return self.name class C: __slots__ = "name" def __init__(self, name): self.name = name def getName(self): return self.name  When I use the dir() on type A and on an object of type A, the attribute __dict__ appears in the result list, as expected. dir(A) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getName'] dir(A("test")) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getName', 'name']  If I use type C I get print(dir(C)) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'classAttributeC', 'getName', 'name'] print(dir(C("test"))) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'classAttributeC', 'getName', 'name']  No attribute __dict__ in the results list for dir(C("test")), as expected but also no attribute __dict__ for dir(C). Why isn't the attribute in the results list when I can call C.__dict__ and get the following output? {'__module__': '__main__', 'classAttributeC': 9999, '__slots__': 'name', '__init__': <function C.__init__ at 0x7ff26b9ab730>, 'getName': <function C.getName at 0x7ff26b9ab7b8>, 'name': <member 'name' of 'C' objects>, '__doc__': None} 

Answer: Since you don't override __dir__ here, in each case here it will resolve in the MRO to type.__dir__(A) or type.__dir__(C). So we look at the default implementation of __dir__ for types, here in Objects/typeobject.c /* __dir__ for type objects: returns __dict__ and __bases__. We deliberately don't suck up its __class__, as methods belonging to the metaclass would probably be more confusing than helpful. */ static PyObject * type___dir___impl(PyTypeObject *self) { PyObject *result = NULL; PyObject *dict = PyDict_New(); if (dict != NULL && merge_class_dict(dict, (PyObject *)self) == 0) result = PyDict_Keys(dict); Py_XDECREF(dict); return result; }  The bases are the same (object,), so there is your answer in the __dict__: >>> "__dict__" in A.__dict__ True >>> "__dict__" in C.__dict__ False  So, types without slots implement a __dict__ descriptor, but types which implement slots don't - and you just get a __dict__ implementation from above: >>> inspect.getattr_static(A, "__dict__") <attribute '__dict__' of 'A' objects> >>> inspect.getattr_static(C, "__dict__") <attribute '__dict__' of 'type' objects>