OOP: Methods and Variables
Constructor, Instance Methods, and Class vs Instance Variables
In the previous unit, we introduced classes and objects. Now let's dig deeper into methods, functions that live inside classes, and understand the difference between class variables and instance variables.

The __init__ Method
The __init__ method is a special method called the constructor. Python calls it automatically when you create an object, and it's where you set up the object's initial state.
class Circle:
def __init__(self, radius):
self.radius = radius
c = Circle(10)
When I create a Circle with Circle(10), Python calls __init__ and passes 10 as the radius argument. The self.radius = radius line stores that value as an attribute on the object.
The self parameter is worth understanding. It's always the first argument to __init__ (and to all instance methods), but you don't pass it explicitly. Python handles it automatically. It's a reference to the object being created or accessed.
Instance Methods
Instance methods are functions defined inside a class that can access the object's attributes through self. Here's the Circle class with an area method:
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
The area method takes self as its only parameter, giving it access to self.radius. When you call c.area() on a Circle object, Python passes the object as self automatically.
Class Variables vs Instance Variables
Python classes have two kinds of variables, and the distinction matters:
Instance variables are unique to each object. The radius attribute we set in __init__ is an instance variable, so each Circle has its own radius value.
Class variables are shared across all instances of the class. If you change a class variable, the change affects every object.
class Circle:
pi = 3.14 # Class variable
def __init__(self, radius):
self.radius = radius # Instance variable
def area(self):
return Circle.pi * self.radius ** 2
Here, pi is defined at the class level, outside any method. All Circle objects share this single pi value. The radius, defined inside __init__ with self.radius, belongs to each individual circle.
Project: Enhanced Shape Class
Let's extend the Shape class from the previous unit by adding methods for perimeter and area calculations:
import turtle
import math
class Shape:
def __init__(self, t, sides, length):
self.t = t
self.sides = sides
self.length = length
def perimeter(self):
return self.sides * self.length
def area(self):
return (self.sides * self.length ** 2) / (4 * math.tan(math.pi / self.sides))
def draw(self):
for _ in range(self.sides):
self.t.forward(self.length)
self.t.right(360 / self.sides)
screen = turtle.Screen()
screen.setup(width=800, height=600)
screen.bgcolor("white")
t = turtle.Turtle()
hexagon = Shape(t, 6, 50)
hexagon.draw()
t.penup()
t.goto(-150, -150)
t.pendown()
t.write(f"Perimeter: {hexagon.perimeter()}", font=("Arial", 16, "normal"))
t.penup()
t.goto(-150, -175)
t.pendown()
t.write(f"Area: {hexagon.area():.2f}", font=("Arial", 16, "normal"))
t.hideturtle()
turtle.done()
The perimeter method multiplies sides by length. The area method uses a formula for regular polygons that involves the tangent function. Each instance method accesses the object's attributes through self, then performs its calculation.
In the next unit, we'll explore inheritance, creating new classes based on existing ones.