Classes and Objects

This section documents the current Python release line as published at the official Python documentation, which is the reference these pages are written and verified against. No specific patch version is pinned.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

A class is a blueprint for objects that bundle state (attributes) and behaviour (methods). Python’s class mechanics are covered in the tutorial’s Classes chapter; this page sticks to what you need to define and use one — the full special-method ("dunder") treatment is on Operator Overloading, and multiple inheritance / MRO on Advanced OOP Design.

class Basics, init, Attributes, and self

A class statement defines a new type. _init_ is the initializer, called automatically right after a new instance is created, and is where instance attributes are usually set:

class Dog:
    species = "Canis familiaris"       # class attribute: shared by all instances

    def __init__(self, name, age):
        self.name = name               # instance attribute: unique per instance
        self.age = age

    def describe(self):                # instance method
        return f"{self.name} is {self.age} year(s) old"

Every method’s first parameter is conventionally named self — it is the instance the method was called on, passed automatically by Python. A class attribute (species above) lives on the class object and is shared by every instance unless an instance sets its own attribute of the same name, which then shadows the class attribute for that instance only:

rex = Dog("Rex", 3)
fido = Dog("Fido", 5)

print(rex.species, fido.species)   # Canis familiaris, Canis familiaris (shared)

rex.species = "Rex's own species"  # creates an *instance* attribute, doesn't touch the class one
print(rex.species, fido.species)   # Rex's own species, Canis familiaris

Mutable class attributes (a list or dict) are a common trap: mutating one through an instance mutates the shared object seen by every instance, so per-instance mutable state belongs in init instead. See the Classes tutorial for the full attribute lookup rules.

Creating Instances; @staticmethod and @classmethod

Calling a class like a function creates an instance — Dog("Rex", 3) runs Dog.init on a freshly created object and returns it. An instance method (the default) receives self and can read or mutate that instance’s state:

print(rex.describe())   # Rex is 3 year(s) old

A @staticmethod takes neither self nor the class — it’s a plain function namespaced under the class, used when the logic doesn’t need instance or class state:

class TemperatureConverter:
    @staticmethod
    def celsius_to_fahrenheit(c):
        return c * 9 / 5 + 32

print(TemperatureConverter.celsius_to_fahrenheit(100))   # 212.0

A @classmethod takes the class itself (conventionally named cls) instead of an instance, and is the idiomatic way to write an alternative constructor:

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_birth_year(cls, name, birth_year, current_year):
        return cls(name, current_year - birth_year)   # cls(...) == Dog(...)

rex = Dog.from_birth_year("Rex", 2021, 2024)
print(rex.name, rex.age)   # Rex 3

Both decorators are documented under staticmethod and classmethod.

Inheritance: class Child(Parent), Overriding, and super()

A class inherits from another by naming it in parentheses; the child gets every attribute and method of the parent and can override any of them by redefining it with the same name:

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} makes a sound"

class Cat(Animal):
    def speak(self):                    # overrides Animal.speak
        return f"{self.name} says Meow"

generic = Animal("Something")
cat = Cat("Whiskers")
print(generic.speak())   # Something makes a sound
print(cat.speak())       # Whiskers says Meow

super() returns a proxy to the parent class, letting an override call the parent’s version instead of fully replacing it — typically to extend init with additional attributes:

class Cat(Animal):
    def __init__(self, name, indoor):
        super().__init__(name)          # runs Animal.__init__, sets self.name
        self.indoor = indoor

    def speak(self):
        base = super().speak()          # reuse the parent's message
        return f"{base} (meow, specifically)"

whiskers = Cat("Whiskers", indoor=True)
print(whiskers.speak())   # Whiskers makes a sound (meow, specifically)
print(isinstance(whiskers, Animal))   # True

Inheritance and super() are covered in the tutorial’s Inheritance section; single inheritance is the common case, and combining several base classes brings in method-resolution-order questions covered on Advanced OOP Design.

repr and str for Basic Display

Without any customization, printing an instance shows an unhelpful default like <main.Dog object at 0x…​>. Two special methods control this: _repr_ should return an unambiguous, developer-facing representation (ideally one that could recreate the object), and _str_ returns a human-readable string used by print() and str() — Python falls back to _repr_ when _str_ is absent:

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!r})"

    def __str__(self):
        return f"{self.name} ({self.age}y)"

rex = Dog("Rex", 3)
print(rex)        # Rex (3y)              -- uses __str__
print(repr(rex))  # Dog(name='Rex', age=3) -- uses __repr__
print([rex])      # [Dog(name='Rex', age=3)] -- containers always use __repr__ on their elements

This is a small slice of Python’s data model — the full catalogue of special methods (operator overloading, comparisons, container protocols, and more) lives under Basic customization in the language reference, and is covered end to end on Operator Overloading.

See Also