Python Interfaces
What is an Interface?
An interface is like an abstract class, except it contains only abstract methods — no implementation whatsoever. Every method simply raises NotImplementedError.
Its sole purpose is to define a contract: any class that implements the interface must implement all of its methods.
⚠️ Python has no
interfacekeyword. Like abstract classes and private attributes, interfaces in Python are a convention, not an enforced language feature. We fake them using a class where every method raisesNotImplementedError.
Interface vs Abstract Class
| Interface | Abstract Class | |
|---|---|---|
| Contains implemented methods? | ❌ Never | ✅ Yes (some methods have logic) |
| Contains abstract methods? | ✅ All methods are abstract | ✅ Some methods are abstract |
| Purpose | Define a contract / type | Provide shared logic + define a contract |
How to spot an interface: if every single method raises NotImplementedError with no other logic, it's an interface.
Defining an Interface in Python
class RunCodeInterface:
def compile_code(self):
raise NotImplementedError("You must implement compile_code")
def execute_code(self):
raise NotImplementedError("You must implement execute_code")
As soon as any method has actual logic (e.g. a print statement), it is no longer a pure interface.
Naming Convention
Suffix the class name with Interface to make its role clear:
class RunCodeInterface: # signals: this is an interface, do not instantiate
Implementing an Interface
In Python, "implementing" an interface means inheriting from it and overriding every method:
class GoCode(RunCodeInterface):
def compile_code(self):
print("Compile go code")
def execute_code(self):
print("Execute go code")
class JavaCode(RunCodeInterface):
def compile_code(self):
print("Compile Java code")
def execute_code(self):
print("Execute Java code")
Both classes implement all interface methods — they satisfy the contract. Extra methods (e.g. test()) can be added freely; the only rule is that the interface methods must be present.
Using Interfaces as a Type Hint
In Python, you can hint (but not enforce) what type a function parameter should be using a colon:
def run_code(code: RunCodeInterface):
code.compile_code()
code.execute_code()
- This tells other developers: "pass something that implements
RunCodeInterface" - Python does not enforce this — you can still pass anything
- In strongly typed languages like Java, passing the wrong type would cause a compile-time error
go = GoCode()
java = JavaCode()
run_code(go) # Compile go code / Execute go code ✅
run_code(java) # Compile Java code / Execute Java code ✅
What You Can and Can't Use Inside a Function
Inside run_code, you should only use methods defined in the interface:
def run_code(code: RunCodeInterface):
code.compile_code() # ✅ guaranteed to exist
code.execute_code() # ✅ guaranteed to exist
code.test() # ⚠️ works for JavaCode but crashes for GoCode — bad practice
The whole point of the interface type hint is that any object passed in is guaranteed to have those methods. Using methods outside the interface breaks that guarantee.
Python vs Strongly Typed Languages (e.g. Java)
| Behaviour | Python | Java |
|---|---|---|
| Interface keyword | ❌ (use a class by convention) | ✅ interface keyword |
| Enforce implementation | ❌ Raises error only at runtime | ✅ Compile-time error |
| Type checking on parameters | ❌ Hints only, not enforced | ✅ Enforced at compile time |
| Using non-interface methods inside a function | ⚠️ Works via duck typing (until it crashes) | ❌ Not allowed |
If an Interface Method Isn't Implemented
class BrokenCode(RunCodeInterface):
pass # forgot to implement compile_code and execute_code
run_code(BrokenCode())
# 💥 NotImplementedError: You must implement compile_code
Python only catches this at runtime (when the method is actually called), not before.
Key Takeaways & Recap
| Concept | Summary |
|---|---|
| Interface | A class where every method raises NotImplementedError — no logic at all |
| Purpose | Define a contract; act as a type for parameters |
| In Python | Implemented via inheritance (no implements keyword) |
| Naming | Suffix with Interface (e.g. RunCodeInterface) |
| Type hints | param: InterfaceName — hints but doesn't enforce the type |
| Most useful in | Strongly typed languages (Java, C#); less critical in Python due to duck typing |
When you see NotImplementedError |
The method is abstract and must be overridden |