PYTHON · STEP 2 · OOP

Python · OOP

Python 3.15 (any 3.10+ works): classes, constructors, methods, inheritance and class-level members — the JavaScript version next to the Python version.

Step 2 of 5Django© Arthur Bernier Jrrewritten · verified9 code blocks287 words

What you will learn#

  • How to Create a Class
  • How to Instantiate a Class
  • Write a Constructor and Methods
  • Create an Inherited Class
  • Write Static Methods/Properties

Below you'll see JavaScript examples of object-oriented patterns and their Python counterparts.

Creating and Instantiating a Class#

In Javascript

JS
// Creating a Classclass Dog {} // Instantiationconst Sparky = new Dog();

In Python

PY
# Creating a class (pass = "nothing here yet")class Dog:    pass # Instantiation: no `new` keyword, just call the classsparky = Dog()

Convention: class names are CapWords, instances and everything else are snake_case.

The Constructor and Methods#

In Javascript

JS
// Creating a Classclass Dog {  // The constructor runs when we instantiate a new instance  constructor(name, age) {    this.name = name;    this.age = age;  }   // A Method  bark() {    console.log(`${this.name} barks`);  }} // Instantiationconst Sparky = new Dog("Sparky", 4);Sparky.bark();

in Python

PY
# Creating a classclass Dog:     # __init__ runs when we instantiate a new instance    def __init__(self, name, age):        self.name = name        self.age = age     # A method: `self` is the instance, passed in automatically    def bark(self):        print(f"{self.name} barks") # Instantiationsparky = Dog("Sparky", 4)sparky.bark()

Where JavaScript has an implicit this, every Python method names the instance explicitly as its first parameter — by convention self. sparky.bark() is sugar for Dog.bark(sparky).

Printing an object shows <__main__.Dog object at 0x…> unless you define __repr__:

PY
class Dog:    def __init__(self, name, age):        self.name = name        self.age = age     def __repr__(self):        return f"Dog(name={self.name!r}, age={self.age})" print(Dog("Sparky", 4))  # Dog(name='Sparky', age=4)

For classes that are mostly data, @dataclass from the standard library writes __init__, __repr__ and __eq__ for you.

Inheritance#

In Javascript

JS
// Creating a Classclass Dog {  // The constructor runs when we instantiate a new instance  constructor(name, age) {    this.name = name;    this.age = age;  }   // A Method  bark() {    console.log(`${this.name} barks`);  }} class SmallDog extends Dog {  constructor(name, age) {    //Super calls the constructor of the parent class    super(name, age);  }   //This will override the version of bark in the parent class  bark() {    console.log(`${this.name} yaps`);  }} // Instantiationconst Sparky = new SmallDog("Sparky", 4);Sparky.bark();

in Python

PY
# Creating a classclass Dog:     def __init__(self, name, age):        self.name = name        self.age = age     def bark(self):        print(f"{self.name} barks") # The parent class goes in parenthesesclass SmallDog(Dog):     def __init__(self, name, age):        # super() reaches the parent class; call its __init__ explicitly        super().__init__(name, age)     # This overrides the parent's bark    def bark(self):        print(f"{self.name} yaps") # Instantiationsparky = SmallDog("Sparky", 4)sparky.bark()print(isinstance(sparky, Dog))  # True

If a subclass doesn't define __init__, the parent's runs automatically — so SmallDog's constructor above could be deleted with no change in behaviour. Python also allows multiple parents (class A(B, C):); the method resolution order is left to right.

Static Methods and Properties#

In Javascript

JS
// Static properties/methods belong to the class, not the instanceclass Calculator {  static lastResult = 0;   // a table of operator functions instead of eval()  static operations = {    "+": (a, b) => a + b,    "-": (a, b) => a - b,    "*": (a, b) => a * b,    "/": (a, b) => a / b,  };   static calculate(num1, num2, operator) {    Calculator.lastResult = Calculator.operations[operator](num1, num2);    return Calculator.lastResult;  }   static showLastResult() {    console.log(Calculator.lastResult);  }} Calculator.calculate(2, 2, "+");Calculator.showLastResult();

In Python

PY
import operator # Class attributes and class/static methods belong to the class, not the instanceclass Calculator:    # Attributes declared in the class body (outside __init__) are class attributes    last_result = 0     # the standard library already has the operator functions    operations = {        "+": operator.add,        "-": operator.sub,        "*": operator.mul,        "/": operator.truediv,    }     @classmethod  # receives the class (cls) instead of an instance (self)    def calculate(cls, num1, num2, op):        cls.last_result = cls.operations[op](num1, num2)        return cls.last_result     @staticmethod  # receives neither self nor cls: a plain function living in the class namespace    def show_last_result():        print(Calculator.last_result) Calculator.calculate(2, 2, "+")Calculator.show_last_result()

Two decorators where JavaScript has one keyword: @classmethod when the method needs the class (alternate constructors, shared counters), @staticmethod when it needs nothing from the class at all. Reading a class attribute through an instance works (Calculator().last_result), but assigning through an instance creates a new instance attribute that shadows it — which is why the class method writes cls.last_result.


Resources to Learn More#


See also