Build and return a new class with a `__slots__` attribute.

def _create_slots_class(self):
        """
        Build and return a new class with a `__slots__` attribute.
        """
        base_names = self._base_names
        cd = {
            k: v
            for k, v in iteritems(self._cls_dict)
            if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
        }

        weakref_inherited = False

        # Traverse the MRO to check for an existing __weakref__.
        for base_cls in self._cls.__mro__[1:-1]:
            if "__weakref__" in getattr(base_cls, "__dict__", ()):
                weakref_inherited = True
                break

        names = self._attr_names
        if (
            self._weakref_slot
            and "__weakref__" not in getattr(self._cls, "__slots__", ())
            and "__weakref__" not in names
            and not weakref_inherited
        ):
            names += ("__weakref__",)

        # We only add the names of attributes that aren't inherited.
        # Settings __slots__ to inherited attributes wastes memory.
        slot_names = [name for name in names if name not in base_names]
        if self._cache_hash:
            slot_names.append(_hash_cache_field)
        cd["__slots__"] = tuple(slot_names)

        qualname = getattr(self._cls, "__qualname__", None)
        if qualname is not None:
            cd["__qualname__"] = qualname

        # __weakref__ is not writable.
        state_attr_names = tuple(
            an for an in self._attr_names if an != "__weakref__"
        )

        def slots_getstate(self):
            """
            Automatically created by attrs.
            """
            return tuple(getattr(self, name) for name in state_attr_names)

        hash_caching_enabled = self._cache_hash

        def slots_setstate(self, state):
            """
            Automatically created by attrs.
            """
            __bound_setattr = _obj_setattr.__get__(self, Attribute)
            for name, value in zip(state_attr_names, state):
                __bound_setattr(name, value)
            # Clearing the hash code cache on deserialization is needed
            # because hash codes can change from run to run. See issue
            # https://github.com/python-attrs/attrs/issues/482 .
            # Note that this code only handles setstate for slotted classes.
            # For dict classes, see similar code in _patch_original_class .
            if hash_caching_enabled:
                __bound_setattr(_hash_cache_field, None)

        # slots and frozen require __getstate__/__setstate__ to work
        cd["__getstate__"] = slots_getstate
        cd["__setstate__"] = slots_setstate

        # Create new class based on old class and our methods.
        cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd)

        # The following is a fix for
        # https://github.com/python-attrs/attrs/issues/102.  On Python 3,
        # if a method mentions `__class__` or uses the no-arg super(), the
        # compiler will bake a reference to the class in the method itself
        # as `method.__closure__`.  Since we replace the class with a
        # clone, we rewrite these references so it keeps working.
        for item in cls.__dict__.values():
            if isinstance(item, (classmethod, staticmethod)):
                # Class- and staticmethods hide their functions inside.
                # These might need to be rewritten as well.
                closure_cells = getattr(item.__func__, "__closure__", None)
            else:
                closure_cells = getattr(item, "__closure__", None)

            if not closure_cells:  # Catch None or the empty list.
                continue
            for cell in closure_cells:
                if cell.cell_contents is self._cls:
                    set_closure_cell(cell, cls)

        return cls