---
title: 'Class and Instance'
source: 'https://academia.sh/en/courses/python-object-and-types/class-and-instance'
course: 'Object-Oriented Python and Types'
language: en
updated: '2026-08-17T18:10:29+00:00'
license: 'CC BY-SA 4.0'
---

# Class and Instance

An attribute written in the class body is shared as 1 object across three instances; one written in the instance body produces 3 separate objects. `self` is not a keyword — it is the instance carried by the bound method built at the moment of access.

The Data Structures and Functional Tools course counted a container's cost and closed on a
line: **choosing a container and writing one are separate things.** Every protocol measured
so far worked on objects the language already gave — a list had a length, a tuple could be a
key, a dict could be compared. None of it was a contract we wrote; each was a ready-made
property of a chosen container.

This course sits on the other side of that line: **we write the side that takes part in the
protocol.** And writing something does not mean it actually answers a call. The course has
one question: **who answers the call?** The first lesson builds the smallest form of that
question. When a class is defined, two separate namespaces come into being — the class
itself, and every instance built from it. When an attribute is read, which of the two does
the answer come from, and where is that name `self` born?

## Two Separate Namespaces

When a `class` statement runs, the interpreter runs the body **once** and writes the names
produced in the body into the class object's dict. A class is an object that exists at
runtime; the methods, too, are ordinary functions sitting inside that dict.

Every instance, in turn, arrives with its **own** dict. When `self.name = ...` is written
inside `__init__`, the name is written not to the class but to that instance's dict. When an
attribute is read, the lookup checks the instance's dict first, then the class's, then the
class's ancestors. **Whoever is found first gives the answer.** The shared rig's
`answering_class` function writes the class side of this lookup out: it says which class
first carries a name during resolution.

`__init__`'s name follows from this arrangement too. When an instance call is made, an empty
object is built **first**, and `__init__` runs **on** that object **afterward** — so
`__init__` does not produce an object, it fills the dict of an object that has already been
built. This is why it returns nothing — it has no object to return, it has an object it was
given.

The measurement's assumptions:

- **CD1** — The measured class is the shared rig's `Record` class; a class attribute (`kind`)
  has been added to its body, and the `source` and `format` capabilities are unchanged.
- **CD2** — Three instances are built from the same class with a single comprehension; the
  only difference between them is the name given to `__init__`.
- **CD3** — The "separate object" column compares the value seen by the first two instances
  with `is`; **the identity number itself is not printed.**
- **CD4** — The "in instance dict" column counts how many instances carry the name in their
  **own** dict; names coming from the class do not count toward this number.

```python
"""Where an attribute stands: the class body versus the instance body."""


class Record:
    """The shared rig's base class; two capabilities are used here."""

    kind = "record"                       # written in the class body

    def __init__(self, name):
        self.name = name                  # written in the instance body

    def source(self):
        return "Record"

    def format(self):
        return f"<{self.source()}>"


def answering_class(cls, name):
    """Which class provides an attribute: the first one found during resolution."""
    for s in cls.__mro__:
        if name in s.__dict__:
            return s.__name__
    return None


trio = [Record(f"r{i}") for i in range(3)]

print(f"{'attribute':<10s} {'answering':>11s} {'separate object':>16s} "
      f"{'in instance dict':>17s}")
for name in ("kind", "name"):
    separate = getattr(trio[0], name) is not getattr(trio[1], name)
    local = sum(1 for t in trio if name in t.__dict__)
    print(f"{name:<10s} {answering_class(Record, name) or 'instance':>11s} {str(separate):>16s} "
          f"{local:>17d}")

a, b = Record("a"), Record("b")
print(f"\n{'at start':<19s}a.kind={a.kind!r} b.kind={b.kind!r} Record.kind={Record.kind!r} "
      f"kind in a's dict -> {'kind' in a.__dict__}")
a.kind = "custom"
print(f"{'a.kind assigned':<19s}a.kind={a.kind!r} b.kind={b.kind!r} Record.kind={Record.kind!r} "
      f"kind in a's dict -> {'kind' in a.__dict__}")
del a.kind
print(f"{'attribute deleted':<19s}a.kind={a.kind!r} b.kind={b.kind!r} Record.kind={Record.kind!r} "
      f"kind in a's dict -> {'kind' in a.__dict__}")
```

```
attribute    answering  separate object  in instance dict
kind            Record            False                 0
name          instance             True                 3

at start           a.kind='record' b.kind='record' Record.kind='record' kind in a's dict -> False
a.kind assigned    a.kind='custom' b.kind='record' Record.kind='record' kind in a's dict -> True
attribute deleted  a.kind='record' b.kind='record' Record.kind='record' kind in a's dict -> False
```

The first table shows the two names standing in two separate places. When `kind` is read,
the answer comes from **`Record`**; all three instances see the same object, and **none** of
them carries this name in its own dict — the count is **0**. When `name` is read, no class
answers; all three instances carry it in their own dict, the count is **3**, and the objects
they see are separate.

The bottom section is a direct consequence of lookup order. `a.kind = "custom"` does **not**
change the name on the class; it opens a new entry in `a`'s dict, and since that entry is
found first, it **shadows** the class's. `b` and the class stay exactly as they were. Once
the instance's name is deleted, the shadow lifts and `a.kind` reads the class's value again.
Assigning to an instance never
touches the class — **the only way to change the class is to write to the class.**

## The Class Body Runs Once

The distinction above has a cost side, and it goes unnoticed in careless writing: the class
body runs **once**, at definition time; the instance body (`__init__`) runs **on every
instance**. Writing `= []` in the class body builds a single list, and every instance shares
that same list.

- **CD5** — The measured class deliberately defines two names of the same kind in two
  separate bodies; there is no difference between them other than the names.
- **CD6** — Three instances are built, and each one appends **its own index** to both
  containers; what is measured is how many items each instance sees at the end.
- **CD7** — Sharing is shown with `is`.

```python
class Shared:
    """Defines two names of the same kind in separate bodies: one in the class, one in the instance."""

    shared_box = []                     # class body: runs once

    def __init__(self):
        self.own_box = []          # instance body: runs per instance


trio = [Shared() for _ in range(3)]
for i, n in enumerate(trio):
    n.shared_box.append(i)
    n.own_box.append(i)

print(f"\n{'attribute':<14s} {'containers made':>16s} {'each instance sees':>20s} "
      f"{'shared':>13s}")
print(f"{'shared_box':<14s} {1:16d} {str([len(n.shared_box) for n in trio]):>20s} "
      f"{str(trio[0].shared_box is trio[2].shared_box):>13s}")
print(f"{'own_box':<14s} {3:16d} {str([len(n.own_box) for n in trio]):>20s} "
      f"{str(trio[0].own_box is trio[2].own_box):>13s}")
```

```
attribute       containers made   each instance sees        shared
shared_box                    1            [3, 3, 3]          True
own_box                       3            [1, 1, 1]         False
```

Three instances each made one append to a container. The class body's container was built
**1** time, so all three appends went into the same list, and every instance sees **3**
items. The instance body's container was built **3** times, and each instance sees only what
it appended itself — **1** item. The numbers come from the same rows; the only thing that
separates them is where the body sits.

A writing rule follows from this: **a mutable value is not written in the class body.** The
class body is for constants, numbers, and immutable values — for those, sharing has no
observable consequence, because no one can mutate them in place. Any state that belongs to
one instance is set up inside `__init__`. The correct use of a class attribute shows up in
the same table: `kind` in the first measurement is a **default**, and an instance only
shadows it when needed; one object is enough for three instances, because nobody mutates it
in place.

## `self` Is Not a Keyword

An object sitting in the class dict is an ordinary function, and its first parameter is no
different from any other name. When accessed through an instance, a step is inserted: the
access produces a **bound method** object that holds both the function and the instance
together. This is why we do not write the first argument in the call — that argument is
already bound at the moment of access.

- **CD8** — The measurement continues with the first block's `Record` class; no new
  definition is made.
- **CD9** — The same call is made in two forms: through the instance, and through the class
  with the instance passed by hand. What is measured is whether the two forms give the
  **same result**.
- **CD10** — The objects' type is printed as a name; **identity numbers and memory data are
  not printed.**
- **CD11** — The call in the last line is deliberately made without an instance; the
  exception's **name** is recorded.

```python
k = Record("k")
print(f"\nk.format() -> {k.format()} | Record.format(k) -> {Record.format(k)} | "
      f"equal -> {k.format() == Record.format(k)}")
print(f"type of object in class dict -> "
      f"{type(Record.__dict__['format']).__name__}")
print(f"type of object accessed via instance -> {type(k.format).__name__}")
print(f"bound method holds instance k -> {k.format.__self__ is k}")
print(f"k.format is k.format -> {k.format is k.format} | "
      f"Record.format is Record.format -> {Record.format is Record.format}")
print(f"function wrapped by bound method -> {k.format.__func__ is Record.format}")

try:
    Record.format()
except TypeError as e:
    print(f"call without instance -> {type(e).__name__}")

print()
print(f"{'capability':<10s} {'answering class':>17s}")
for name in ("source", "format", "__init__"):
    print(f"{name:<10s} {answering_class(Record, name):>17s}")
print(f"{'name':<10s} {answering_class(Record, 'name') or '—':>17s}")
```

```
k.format() -> <Record> | Record.format(k) -> <Record> | equal -> True
type of object in class dict -> function
type of object accessed via instance -> method
bound method holds instance k -> True
k.format is k.format -> False | Record.format is Record.format -> True
function wrapped by bound method -> True
call without instance -> TypeError

capability   answering class
source                Record
format                Record
__init__              Record
name                       —
```

The first line shows the two forms doing the same job: `k.format()` gives the same result as
`Record.format(k)`. The second is the unfolded form of the first. The next two lines name
the step in between — the object sitting in the class dict is a **function**, the object
accessed through the instance is a **method**. The fourth line says what the method carries:
the instance the access was made through.

The fifth line proves that binding happens **at the moment of access**. Reading the same
name twice produces two separate bound-method objects; the `is` comparison gives `False`.
Accessing through the class involves no binding — the same function in the dict comes back
every time, and the comparison gives `True`. The sixth line ties the two together: the
function wrapped by the bound method is the **very same** function read from the class. This
is also why the instance-less call raises `TypeError` — the function expected a parameter,
and there was no instance to bind it.

This has two everyday consequences. First, a bound method carries as a **value** without
being called: passing `k.format` somewhere carries `k` with it, since the object holds the
instance inside itself — putting a method into a callback list puts the instance in too.
Second, a method can always be read off the class and called by hand; the instance is not a
hidden argument, it is an explicit, writable first one.

Object-oriented programming's concepts were built in the Programming Fundamentals course;
**they are not repeated here.** There, a class was a template and an instance one production
of it. What is measured here is that the template itself is also an **object**, and which
dict the answer comes from. The last table closes this: **`Record`** answers all four names,
and **no** class answers the `name` attribute — it is not written in any class, it is born
separately in every instance.

## Three Forms of Binding

Since binding is a rule, it can be changed. Three separate binding forms can be defined in
the same class body: a method whose first argument is bound to the **instance**, one bound
to the **class**, and one bound to **nothing**. All three sit in the same body and are called
the same way; the only place they differ is what the first argument is at call time.

- **CD12** — Three methods are defined in a single class body, and all three do the same
  job: return the name of whatever is bound to them. If nothing is bound, a dash is returned
  in its place.
- **CD13** — The measurement is made through a **subclass**; the class that writes the bodies
  and the class the call is made on are deliberately separated.
- **CD14** — The "call" columns call the method **with no arguments**; a call that cannot be
  satisfied falls with an exception, and the **exception's name** is recorded with an
  exclamation prefix.
- **CD15** — The access columns print the returned object's type as a name; **identity
  numbers are not printed.**

```python
class Formatter:
    """Three binding forms in the same body: bound to the instance, the class, and nothing."""

    def instance_method(self):
        return type(self).__name__

    @classmethod
    def class_method(cls):
        return cls.__name__

    @staticmethod
    def static_method():
        return "—"


class SubFormatter(Formatter):
    pass


def attempt(call):
    try:
        return call()
    except TypeError as e:
        return f"!{type(e).__name__}"


n = SubFormatter()
print(f"\n{'method':<15s} {'class access':>15s} {'instance access':>15s} "
      f"{'class call':>15s} {'instance call':>15s}")
for name in ("instance_method", "class_method", "static_method"):
    print(f"{name:<15s} {type(getattr(SubFormatter, name)).__name__:>15s} "
          f"{type(getattr(n, name)).__name__:>15s} "
          f"{attempt(getattr(SubFormatter, name)):>15s} "
          f"{attempt(getattr(n, name)):>15s}")

print(f"\nclass that wrote the body {answering_class(SubFormatter, 'class_method')}, "
      f"class bound to cls {SubFormatter.class_method()}")
```

```
method             class access instance access      class call   instance call
instance_method        function          method      !TypeError    SubFormatter
class_method             method          method    SubFormatter    SubFormatter
static_method          function        function               —               —

class that wrote the body Formatter, class bound to cls SubFormatter
```

The table shows row by row where binding happens. The instance method is bound only when
accessed **through the instance**; the object accessed through the class is a bare function,
and calling it with no arguments falls with `TypeError`. The class method is bound on
**both** kinds of access — even read through the class it comes back as a method, because
the thing to bind is already the class itself; the no-argument call works either way. The
static method is bound on neither access; a bare function comes back both ways, and both
calls report that there is nothing bound.

**Five** of the six calls land, **one** falls. The falling call is not a gap, it is the rule
itself: an instance method cannot be called without an instance, because there is nothing to
fill its first parameter.

The last line is the first sharp form of the course's question. `class_method`'s body is
written in **`Formatter`**; but because the call is made through `SubFormatter`, the class
bound to `cls` is **`SubFormatter`**. The class that writes the body and the context that
answers the call are not the same thing — the body sits in one place, the binding happens at
call time. What the next lesson measures is this same distinction, enlarged.

## Summary

- Class and instance are two separate namespaces; attribute lookup checks the instance's
  dict first, then the class's, and **whoever is found first gives the answer.**
- `kind` in the class body is shared as **1** object across three instances and is not found
  in any of their dicts; `name` inside `__init__` produces **3** separate objects and sits in
  all three dicts.
- Assigning to an instance does not change the class, it shadows it; once the instance's name
  is deleted, the class's value becomes visible again.
- The class body runs once, the instance body runs per instance: a container defined in the
  class is built **1** time and holds all **3** appends together; one defined in the instance
  is built **3** times.
- `self` is not a keyword: access through an instance produces a new **bound method** every
  time, that method carries the instance it was accessed through, and passes it as the first
  argument at call time.
- There are three forms of binding; **5** of six calls land, and the one that falls is an
  instance method called without an instance. A class method whose body is written in
  `Formatter`, when called through `SubFormatter`, binds **`SubFormatter`** to `cls`.

## Next Step

In this lesson the one that always answered was `Record`, because there was only one class
and lookup ended on the first step. When classes are derived from each other, lookup gets
longer: a name may be written in more than one class, and **resolution order** decides which
one is found. The next lesson measures that order and pays off the course's second claim —
across an inheritance tree, which classes does the body of four capabilities spread across;
how many of the same four capabilities does a class built with composition write in its own
body; and why does a method whose body is written in one class print another class's name?
