Methods and Attributes: Mastering OOP State and Behavior
Learn how to define instance methods, access class attributes, and master the 'self' keyword to build powerful, stateful objects in Python.

Previously in this course, we explored Introduction to Object-Oriented Programming (OOP) in Python, where we learned how to define a basic class and initialize objects using the __init__ constructor. Now that you can create "data containers," it's time to give those objects intelligence by adding behavior.
In this lesson, we will focus on how to use instance methods, access attributes, and correctly use the self keyword to manage the internal state of your objects.
Understanding Attributes and State
In OOP, an attribute is simply a variable that belongs to an object. It represents the "state" of that specific instance. While __init__ sets the initial state, attributes can (and often should) be accessed or modified by methods later in the object's lifecycle.
Think of a class like a blueprint for a DataPoint in our ongoing project. The attributes are the specific details—like a value or a timestamp—that belong to one unique instance of that data point.
Defining and Using Instance Methods

An instance method is a function defined inside a class that operates on the object's data. Unlike regular functions, instance methods have access to the specific instance they are called on.
The secret to this access is the self parameter. When you call my_object.method(), Python automatically passes my_object as the first argument to that method. We capture this reference in the parameter named self.
A Concrete Example: The DataProcessor
Let’s advance our project by creating a class that handles data processing. We want to be able to add a raw value and then format it.
PYTHONclass DataProcessor: def __init__(self, name): self.name = name self.values = [] # An attribute to store state def add_value(self, value): CE9178">"""Adds a value to our instance state.""" self.values.append(value) print(f"{self.name} added value: {value}") def get_average(self): CE9178">"""Calculates the average using instance attributes.""" if not self.values: return 0 return sum(self.values) / len(self.values) # Usage processor = DataProcessor("SensorA") processor.add_value(10) processor.add_value(20) avg = processor.get_average() print(f"The average for {processor.name} is {avg}")
In this code:
self.values: We access the list associated with this specificDataProcessorinstance.self.name: We access the instance attribute to provide context in our print statement.self: By including it as the first argument, we ensure the method knows which object's data to manipulate.
The Role of 'self'
A common confusion for beginners is why we must write self even when we don't use it in every line of the method. In Python, self is not a keyword (like class or def); it is a convention. You could name it this, but self is the standard followed by every professional Python developer.
Without self, your method would be an isolated function that knows nothing about the object’s attributes. It acts as the "bridge" between the method logic and the object's data.
Hands-on Exercise
Create a class called UserSession that tracks a username and the number of pages visited.
- Initialize the class with a
usernameattribute and apage_countattribute (start at 0). - Create a method
visit_page()that incrementspage_countby 1. - Create a method
get_summary()that returns a string:"User [name] has visited [count] pages." - Instantiate the object, call
visit_page()three times, and print the result ofget_summary().
Common Pitfalls

- Forgetting
selfin the parameter list: If you definedef method():instead ofdef method(self):, you will encounter aTypeErrorwhen you try to call it because Python will still try to pass the object instance as an argument. - Accessing attributes without
self.: If you try to accessvaluesinside a method instead ofself.values, Python will look for a local variable namedvaluesand fail, because class attributes are scoped to the instance. - Confusing Class Attributes vs. Instance Attributes: Everything we've done here uses
self, which creates instance attributes (unique to each object). If you define a variable directly under theclassline (outside of any method), it becomes a class attribute, which is shared by all instances. Avoid this until you are comfortable with instance-level state.
FAQ
Can I call one instance method from another?
Yes! Use self.method_name() to call another method within the same class.
Why does Python force me to write self?
It makes the code explicit. You always know when a method is interacting with instance state because self is clearly visible in the argument list.
Can I change an attribute value from outside the class?
Yes, you can do processor.name = "NewName", but it's often better practice to provide a method (like set_name()) to handle the update so you can add validation logic later.
Recap

In this lesson, we moved beyond static data and implemented dynamic behavior. By using instance methods, we can define how our objects act, and by using attributes via self, we ensure that each object maintains its own unique state. These concepts form the foundation of encapsulation, one of the core pillars of object-oriented programming.
Up next: Inheritance, where we learn how to create specialized versions of our classes to promote code reuse.



