Issue #26186: Remove the restriction that built-in and extension
modules  can't be lazily loaded.

Thanks to Python 3.6 allowing for types.ModuleType to have its
__class__ mutated, the restriction can be lifted by calling
create_module() on the wrapped loader.
diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
index a9d0f1e..6bdf0d4 100644
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -204,11 +204,6 @@
     return module_for_loader_wrapper
 
 
-class _Module(types.ModuleType):
-
-    """A subclass of the module type to allow __class__ manipulation."""
-
-
 class _LazyModule(types.ModuleType):
 
     """A subclass of the module type which triggers loading upon attribute access."""
@@ -218,13 +213,14 @@
         # All module metadata must be garnered from __spec__ in order to avoid
         # using mutated values.
         # Stop triggering this method.
-        self.__class__ = _Module
+        self.__class__ = types.ModuleType
         # Get the original name to make sure no object substitution occurred
         # in sys.modules.
         original_name = self.__spec__.name
         # Figure out exactly what attributes were mutated between the creation
         # of the module and now.
-        attrs_then = self.__spec__.loader_state
+        attrs_then = self.__spec__.loader_state['__dict__']
+        original_type = self.__spec__.loader_state['__class__']
         attrs_now = self.__dict__
         attrs_updated = {}
         for key, value in attrs_now.items():
@@ -239,9 +235,9 @@
         # object was put into sys.modules.
         if original_name in sys.modules:
             if id(self) != id(sys.modules[original_name]):
-                msg = ('module object for {!r} substituted in sys.modules '
-                       'during a lazy load')
-                raise ValueError(msg.format(original_name))
+                raise ValueError(f"module object for {original_name!r} "
+                                  "substituted in sys.modules during a lazy "
+                                  "load")
         # Update after loading since that's what would happen in an eager
         # loading situation.
         self.__dict__.update(attrs_updated)
@@ -275,8 +271,7 @@
         self.loader = loader
 
     def create_module(self, spec):
-        """Create a module which can have its __class__ manipulated."""
-        return _Module(spec.name)
+        return self.loader.create_module(spec)
 
     def exec_module(self, module):
         """Make the module load lazily."""
@@ -286,5 +281,8 @@
         # on an object would have triggered the load,
         # e.g. ``module.__spec__.loader = None`` would trigger a load from
         # trying to access module.__spec__.
-        module.__spec__.loader_state = module.__dict__.copy()
+        loader_state = {}
+        loader_state['__dict__'] = module.__dict__.copy()
+        loader_state['__class__'] = module.__class__
+        module.__spec__.loader_state = loader_state
         module.__class__ = _LazyModule
diff --git a/Lib/test/test_importlib/test_lazy.py b/Lib/test/test_importlib/test_lazy.py
index cc383c2..ffd8dc6 100644
--- a/Lib/test/test_importlib/test_lazy.py
+++ b/Lib/test/test_importlib/test_lazy.py
@@ -66,6 +66,8 @@
         spec = util.spec_from_loader(TestingImporter.module_name,
                                      util.LazyLoader(loader))
         module = spec.loader.create_module(spec)
+        if module is None:
+            module = types.ModuleType(TestingImporter.module_name)
         module.__spec__ = spec
         module.__loader__ = spec.loader
         spec.loader.exec_module(module)