def astype(self, out_dtype):
        """Return a copy of this space with new ``out_dtype``.

        Parameters
        ----------
        out_dtype :
            Output data type of the returned space. Can be given in any
            way `numpy.dtype` understands, e.g. as string (``'complex64'``)
            or built-in type (``complex``). ``None`` is interpreted as
            ``'float64'``.

        Returns
        -------
        newspace : `FunctionSpace`
            The version of this space with given data type
        """
        out_dtype = np.dtype(out_dtype)
        if out_dtype == self.out_dtype:
            return self

        # Try to use caching for real and complex versions (exact dtype
        # mappings). This may fail for certain dtype, in which case we
        # just go to `_astype` directly.
        real_dtype = getattr(self, 'real_out_dtype', None)
        if real_dtype is None:
            return self._astype(out_dtype)
        else:
            if out_dtype == real_dtype:
                if self.__real_space is None:
                    self.__real_space = self._astype(out_dtype)
                return self.__real_space
            elif out_dtype == self.complex_out_dtype:
                if self.__complex_space is None:
                    self.__complex_space = self._astype(out_dtype)
                return self.__complex_space
            else:
                return self._astype(out_dtype)