PYTHON • OBJECT-ORIENTED PROGRAMMING

Instance Attributes & Methods — Define instance attributes and methods; use self correctly

Learn how Python objects carry their own data and behaviors through instance attributes and methods.

Historical Context & Motivation

Before object-oriented programming (OOP) existed, programmers wrote code as long sequences of instructions with data stored in separate, unconnected variables. As programs grew larger, keeping track of which data belonged to which part of the program became a nightmare. Imagine trying to manage the stats for 500 video-game characters when every attribute — health, speed, name — is just a loose variable floating around. OOP emerged to solve this chaos by bundling data and the functions that operate on that data into a single unit called an object.

1967
Simula Introduces Objects
Norwegian computer scientists Ole-Johan Dahl and Kristen Nygaard created Simula, the first language to feature classes and objects, originally designed to model real-world simulations.
1972
Smalltalk Refines OOP
Alan Kay's team at Xerox PARC developed Smalltalk, which made everything an object and introduced the concept of message passing — the ancestor of method calls.
1991
Python Is Born
Guido van Rossum released Python 0.9.0, which included classes with inheritance. Python's OOP model drew from C++ and Modula-3, emphasizing readability and simplicity.
2000s
Python Becomes Mainstream
Python's clean OOP syntax made it a favorite for teaching programming. The explicit use of 'self' became one of Python's most distinctive and debated design choices.

The core question that instance attributes and methods address is straightforward: how does each individual object keep track of its own unique data, and how does Python know which object's data to use when you call a method? The answer lies in a special keyword — self — which acts as each object's personal name tag, pointing back to itself so Python always knows whose data it's working with.

Core Principles & Definitions

To understand instance attributes and methods, you first need to grasp a few foundational ideas. A class is a blueprint that describes what data an object will hold and what actions it can perform. An instance is a specific object built from that blueprint — like how a particular house is built from an architectural plan. Each instance can have its own unique values even though they all share the same structure.

1

Instance Attribute

A variable that belongs to one specific object. Each instance stores its own copy. Defined inside __init__ using self.attribute_name.
2

Instance Method

A function defined inside a class that operates on one specific object. Its first parameter is always self, which gives it access to that object's attributes.
3

The self Parameter

A reference to the current instance. Python automatically passes the object as the first argument when you call a method, so you never write it in the parentheses yourself.
4

The __init__ Method

A special method (called a constructor) that Python runs automatically when you create a new object. This is where you set up instance attributes with their initial values.
✦ KEY TAKEAWAY
Think of a class like a student ID card template — it has blank fields for name, grade, and student number. Each actual card (instance) gets filled in with a specific student's information (instance attributes). The self keyword is like the word "my" on the card — when a card says "my name," it always refers to the person holding that particular card.

Visual Explanation — How self Connects Objects to Their Data

The diagram below shows how a single class blueprint produces two separate instances, each with its own data. Notice how self inside each method always refers back to the specific instance that called it. When dog1.bark() is called, self points to dog1; when dog2.bark() is called, self points to dog2.

The class Dog defines the blueprint. Two instances — dog1 and dog2 — each store their own name and age. The self reference inside each instance always points back to that particular object.

How It Works — The Mechanics of self

Understanding the mechanism behind self is the key to mastering instance attributes and methods. When you write dog1.bark(), Python secretly translates this into Dog.bark(dog1). The object before the dot gets passed as the first argument to the method — and that first parameter is self. This is why every instance method must list self as its first parameter, even though you never pass it yourself when calling the method.

The __init__ Constructor

The __init__ method (pronounced "dunder init") is a special method that runs automatically the moment you create a new instance. Its job is to initialize instance attributes by attaching data to self. For example, self.name = name takes the value passed in through the name parameter and stores it as an attribute on the specific object being created. Without self, the variable would be local to the method and would disappear once __init__ finishes running.

Writing Instance Methods

An instance method is any function defined inside a class that takes self as its first parameter. Inside the method, you can read or modify instance attributes using self.attribute_name. Methods can also accept additional parameters after self — just like regular functions. The critical rule is: always use self to access or modify the object's data inside a method.

⚠️ Common Mistake Alert
Forgetting self in a method definition is the #1 beginner error. If you write def bark(): instead of def bark(self):, Python will raise a TypeError saying it received 1 argument but expected 0. That "extra" argument is the instance Python tried to pass in!

Anatomy of a Class — Detailed Breakdown

Let's dissect a complete class to see exactly where each piece fits. The diagram below annotates every part of a Student class, showing the relationship between the class definition, the constructor, instance attributes, and instance methods.

Annotated Student class showing the constructor (purple), instance attributes (amber), a modifier method (cyan), an accessor method (green), and a display method (pink).
Key syntax patterns for instance attributes and methods
ComponentSyntax PatternPurpose
Class declarationclass ClassName:Defines the blueprint; name uses CamelCase
Constructordef __init__(self, ...):Initializes attributes when an object is created
Instance attributeself.attr = valueStores data unique to each instance
Instance methoddef method(self, ...):A function that can read/modify the object's data
Calling a methodobj.method(args)Python passes obj as self automatically

Worked Example — Building a BankAccount Class

Let's build a BankAccount class step by step. This example demonstrates how instance attributes store each account's unique balance, and how methods use self to deposit, withdraw, and check the balance.

Creating a BankAccount Class
1
Step 1 — Define the Class and ConstructorStart by writing the class header and the __init__ method. We need two instance attributes: self.owner and self.balance. We'll give balance a default value of 0.
class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance
2
Step 2 — Add a Deposit MethodThe deposit method takes self and an amount parameter. It adds the amount to self.balance. Notice that we use self.balance (not just balance) to modify the object's stored data.
def deposit(self, amount): self.balance += amount return self.balance
3
Step 3 — Add a Withdraw Method with ValidationThe withdraw method checks whether self.balance is large enough before subtracting. This shows how methods can use instance attributes to make decisions. If the balance is too low, we return a warning message instead.
def withdraw(self, amount): if amount > self.balance: return 'Insufficient funds' self.balance -= amount return self.balance
4
Step 4 — Create Instances and TestNow we create two separate accounts. Each has its own owner and balance. Depositing into one account does not affect the other — proving that instance attributes are independent.
acct1 = BankAccount('Alice', 100) acct2 = BankAccount('Bob') acct1.deposit(50) → acct1.balance is 150 acct2.deposit(200) → acct2.balance is 200
5
Step 5 — Verify Independence of InstancesAfter the operations above, acct1.balance is 150 and acct2.balance is 200. Each object's self pointed to a different instance during each method call, so the data stayed separate.
acct1.balance → 150 | acct2.balance → 200 (completely independent)

Instance vs. Class Attributes — Key Differences

Python also supports class attributes — variables defined directly inside the class body (outside any method) that are shared by all instances. It's important to understand how these differ from instance attributes so you choose the right tool for the job.

Instance attributes vs. class attributes
FeatureInstance AttributeClass Attribute
Where definedInside __init__ using self.xDirectly in the class body
ScopeUnique to each objectShared across all objects
When createdEach time an instance is madeOnce, when the class is defined
Typical useUnique data like name, score, IDShared constants like species, school name
Exampleself.name = "Alice"species = "Canis lupus"
💡 WHEN TO USE WHICH
Use an instance attribute when each object should have its own version of the data (like each player's health points in a game). Use a class attribute when the value is the same for every object (like the maximum level cap in that same game). When in doubt, start with instance attributes — they're safer because changing one object won't accidentally affect another.

Connection to Advanced OOP Concepts

Instance attributes and methods are the foundation of OOP, but Python offers more powerful features built on top of them. Understanding self and instance-level data prepares you for inheritance, encapsulation, and polymorphism — the three pillars of object-oriented design.

How today's concepts connect to advanced OOP topics
What You Know NowWhat's Coming Next
Instance attributes store per-object dataEncapsulation — using underscores to protect attributes from outside access
Instance methods use self to access dataInheritance — child classes inherit methods from parent classes and can override them
Each object has its own methodsPolymorphism — different classes can have methods with the same name that behave differently
Regular methods with selfClass & static methods — methods that use cls instead of self, or no special first parameter at all
Attributes accessed directlyProperties (@property) — methods that look like attributes, adding validation or computed values

Every advanced OOP pattern relies on the fact that self gives each object a persistent identity — a way to carry data and behavior together. Once you're comfortable creating classes with instance attributes and methods, you're ready to build complex, real-world programs that model anything from social media feeds to physics simulations.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Explain in your own words why every instance method in Python needs self as its first parameter. What would happen if you forgot to include it?
PROBLEM 2 — BASIC
Write a class called Rectangle with instance attributes width and height, and an instance method area() that returns the area. Then create a rectangle with width 5 and height 3 and print its area.
PROBLEM 3 — INTERMEDIATE
Create a Counter class with a count attribute starting at 0. Write three methods: increment() adds 1, decrement() subtracts 1 (but never below 0), and reset() sets count back to 0. Trace through this sequence and give the final count: c = Counter(); c.increment(); c.increment(); c.increment(); c.decrement(); c.increment().
PROBLEM 4 — APPLIED
Design a Playlist class for a music app. It should store a name and a list of songs (initially empty). Include methods add_song(title), remove_song(title), and total_songs(). Explain why self.songs = [] should go in __init__ rather than as a default parameter like def __init__(self, name, songs=[]).
PROBLEM 5 — CRITICAL THINKING
A student writes the following code and is confused about the output. The class Pet has __init__(self, name) setting self.name = name and self.tricks = []. There is a method def learn_trick(self, trick): self.tricks.append(trick) and another method def show_tricks(self): return self.tricks. The student runs: p1 = Pet('Max'); p2 = Pet('Bella'); p1.learn_trick('sit'); p1.learn_trick('shake'); p2.learn_trick('roll over'). What does p1.show_tricks() return? What does p2.show_tricks() return? Explain how self ensures the tricks stay separate.

Lesson Summary

In this lesson, you learned that a class is a blueprint for creating objects, and an instance is a specific object built from that blueprint. Instance attributes are variables defined in the __init__ constructor using self.attribute = value, and each object gets its own independent copy. Instance methods are functions inside the class that take self as their first parameter, allowing them to read and modify the calling object's data.

The self parameter is the mechanism that connects each method call to the correct object — Python automatically passes the instance as the first argument when you write obj.method(). Remember: always include self in method definitions, always use self.x to access instance attributes, and understand that instance attributes are independent across objects. These fundamentals are the gateway to the full power of object-oriented programming in Python.

Varsity Tutors • Python • Instance Attributes & Methods