Objects · Lesson 13 of 18 · 20 min

Classes and instances

Attributes, self, class vs instance data, and methods.

  • Construct objects with __init__
  • Distinguish class attributes from instance attributes
  • Use instance, class, and static methods

A class is a factory for objects

`class` creates a class object. Calling the class (`Point(1, 2)`) creates an instance. `__init__` is not the constructor — `__new__` allocates — but `__init__` is where you attach attributes to `self`. By convention every instance method takes `self` as the first parameter; the call `p.distance()` binds `p` to `self`.

Attributes live on the instance dict (`p.__dict__`) unless you use slots. Lookup walks the instance, then the class, then base classes. Assignment `self.x = 1` always writes to the instance (unless a data descriptor sits in the way).

A small value type
class Point:
    origin_count = 0

    def __init__(self, x, y):
        self.x = x
        self.y = y
        if x == 0 and y == 0:
            Point.origin_count += 1

    def distance(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

    @classmethod
    def origin(cls):
        return cls(0, 0)

    @staticmethod
    def polar(r, label):
        return f"{label}:{r}"

p = Point(3, 4)
print(p.distance(), Point.origin_count)
print(Point.origin().x, Point.polar(1, "N"))

Three kinds of method

DecoratorFirst argUse
(none)self — the instanceReads/writes instance state
@classmethodcls — the classAlternate constructors
@staticmethodnoneA function namespaced on the class

Representation and equality

Default equality for user classes is identity. If your object is a value, define `__eq__` and `__hash__` together — or set `__hash__ = None` if it is mutable. `__repr__` should look like a constructor call so logs are readable.

eq and repr
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return f"Point({self.x}, {self.y})"
    def __eq__(self, other):
        return isinstance(other, Point) and (self.x, self.y) == (other.x, other.y)

print(Point(1, 2))
print(Point(1, 2) == Point(1, 2))
print(Point(1, 2) == (1, 2))

Check yourself

Quiz

  1. 1.`p.distance()` is equivalent to:

  2. 2.@classmethod is the right tool for:

  3. 3.User classes compare with == by default using:

Practice

Exercise

Write a class `Counter` with `__init__(self, start=0)`, methods `inc(self, n=1)` and `dec(self, n=1)`, and a read-only-feeling `value()` method that returns the current count. `dec` should not go below 0.

Tutor

Ask a question about this lesson. Answers are generated on demand and capped so the session stays focused.