diff --git a/kwant/_common.py b/kwant/_common.py
index 76e952cf6c0d2ffc437d42ca5c093a5825aac0e9..48c45eaac9cb1e4ed4a2971c3bd58e0cebcb1c43 100644
--- a/kwant/_common.py
+++ b/kwant/_common.py
@@ -6,10 +6,12 @@
 # the file AUTHORS.rst at the top-level directory of this distribution and at
 # http://kwant-project.org/authors.
 
+import sys
 import numpy as np
 import numbers
 import inspect
 import warnings
+import importlib
 from contextlib import contextmanager
 
 __all__ = ['KwantDeprecationWarning', 'UserCodeError']
@@ -123,3 +125,26 @@ def get_parameters(func):
     takes_kwargs = any(i.kind is inspect.Parameter.VAR_KEYWORD
                        for i in pars.values())
     return required_params, default_params, takes_kwargs
+
+
+class lazy_import:
+    def __init__(self, module, package='kwant', deprecation_warning=False):
+        if module.startswith('.') and not package:
+            raise ValueError('Cannot import a relative module without a package.')
+        self.__module = module
+        self.__package = package
+        self.__deprecation_warning = deprecation_warning
+
+    def __getattr__(self, name):
+        if self.__deprecation_warning:
+            absolute_module = '.'.join((self.__package, self.__module))
+            msg = ("Accessing {0} without an explicit import is deprecated. "
+                   "Instead, explicitly 'import {0}'."
+                  ).format('.'.join((self.__package, self.__module)))
+            warnings.warn(msg, KwantDeprecationWarning, stacklevel=2)
+        relative_module = '.' + self.__module
+        mod = importlib.import_module(relative_module, self.__package)
+        # Replace this _LazyModuleProxy with an actual module
+        package = sys.modules[self.__package]
+        setattr(package, self.__module, mod)
+        return getattr(mod, name)