Python
dynamic loading
class loading
importlib
Python programming

How to dynamically load a Python class

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Dynamically loading a Python class means resolving the module and class name at runtime instead of importing them statically at the top of the file. This is useful for plugin systems, configurable backends, and factory code, but it should be done carefully because runtime loading moves errors from import time to execution time.

The Basic Pattern

The standard tool is importlib.import_module, followed by getattr to retrieve the class from the module.

python
1import importlib
2
3
4def load_class(module_name: str, class_name: str):
5    module = importlib.import_module(module_name)
6    cls = getattr(module, class_name)
7    return cls
8
9
10MyClass = load_class("collections", "Counter")
11instance = MyClass("banana")
12print(instance)

This pattern separates the two steps clearly:

  • import the module,
  • fetch the named class from that module.

That is usually all you need for straightforward dynamic loading.

Loading from a Dotted Path

A common convenience is to accept one string such as package.module.ClassName and split it into the module part and the class part.

python
1import importlib
2
3
4def load_class_from_path(path: str):
5    module_name, class_name = path.rsplit(".", 1)
6    module = importlib.import_module(module_name)
7    return getattr(module, class_name)
8
9
10CounterClass = load_class_from_path("collections.Counter")
11print(CounterClass("apple"))

This is useful in configuration-driven systems where a JSON or YAML setting names the implementation to load.

Instantiate Only After Validation

Dynamic loading becomes safer if you validate what you loaded before instantiating it. For example, you may want to ensure the loaded object is actually a class or inherits from a required base type.

python
1import importlib
2
3
4class BasePlugin:
5    def run(self):
6        raise NotImplementedError
7
8
9def load_plugin(path: str):
10    module_name, class_name = path.rsplit(".", 1)
11    module = importlib.import_module(module_name)
12    cls = getattr(module, class_name)
13
14    if not issubclass(cls, BasePlugin):
15        raise TypeError(f"{path} is not a valid plugin class")
16
17    return cls

That kind of check prevents configuration mistakes from turning into stranger runtime failures later.

Handle Errors Explicitly

Dynamic imports fail in predictable ways:

  • 'ModuleNotFoundError if the module does not exist,'
  • 'AttributeError if the class name is wrong,'
  • 'TypeError or custom validation failures if the loaded object is not what you expect.'

A small wrapper can turn those into clearer application errors.

python
1import importlib
2
3
4def load_class_safe(path: str):
5    try:
6        module_name, class_name = path.rsplit(".", 1)
7        module = importlib.import_module(module_name)
8        return getattr(module, class_name)
9    except ModuleNotFoundError as exc:
10        raise RuntimeError(f"Module not found in path: {path}") from exc
11    except AttributeError as exc:
12        raise RuntimeError(f"Class not found in path: {path}") from exc

That makes troubleshooting much easier than letting a deep import stack trace leak into unrelated application logic.

Security and Design Considerations

Dynamic loading should not be treated as a free-form input feature for arbitrary user strings. If the module path comes from an untrusted source, you are effectively letting external input influence what code gets imported.

In real systems, prefer one of these patterns:

  • load only from a fixed package,
  • validate against an allowlist,
  • or map friendly configuration names to known implementation paths.

The flexibility is useful, but unrestricted dynamic import is rarely the safest design.

Common Pitfalls

  • Using __import__ directly when importlib.import_module is clearer.
  • Forgetting that module import and class lookup are separate steps.
  • Loading the class successfully but not validating whether it matches the expected interface or base class.
  • Treating untrusted strings as safe import paths.
  • Making debugging harder by scattering dynamic import logic instead of wrapping it in one helper function.

Summary

  • Dynamic class loading in Python is usually done with importlib.import_module and getattr.
  • A dotted path such as package.module.ClassName is a convenient input format.
  • Validate the loaded class before instantiating it if the application expects a specific interface.
  • Handle module and attribute errors explicitly to keep failures understandable.
  • Use dynamic loading carefully when configuration or external input controls the import path.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.