Skip to main content

Defining Classes: Attributes and Methods

In the last article, we learned that a class is a blueprint and an object is the instance we create from it. We used the __init__() method to set up the initial data, or attributes, of an object.

Now, let's expand on that. An object isn't just a container for data; it's also supposed to have behavior. In Python, we define this behavior using methods. This article will explore the two fundamental components of any class: its attributes (the data it holds) and its methods (the actions it can perform).


πŸ“š Prerequisites​

You should understand the basic concept of a class and an object, and how to use the __init__() constructor.


🎯 Article Outline: What You'll Master​

In this article, you will learn:

  • βœ… Instance Attributes: The data that is unique to each object.
  • βœ… Class Attributes: Data that is shared among all objects of a class.
  • βœ… Instance Methods: Functions defined inside a class that can access and modify an object's instance attributes.
  • βœ… The self Parameter: A deeper look at how methods know which object they belong to.

🧠 Section 1: Instance Attributes vs. Class Attributes​

Attributes are the variables associated with a class and its objects. Python has two main types.

Instance Attributes​

We've already seen these! An instance attribute is a variable that belongs to a specific instance of a class. Each object gets its own copy of these attributes. They are defined inside the __init__() method using the self keyword.

class Car:
def __init__(self, make, model):
# These are INSTANCE attributes
self.make = make
self.model = model

car_one = Car("Toyota", "Camry")
car_two = Car("Honda", "Civic")

# Each object has its own unique data
print(f"Car One is a {car_one.make} {car_one.model}")
print(f"Car Two is a {car_two.make} {car_two.model}")

Class Attributes​

A class attribute is a variable that is shared by all instances of a class. It belongs to the class itself, not to any one object. You define it directly inside the class, but outside of any methods.

Think of a class attribute as a default or constant value that all objects of that class should have access to.

class Car:
# This is a CLASS attribute
wheels = 4

def __init__(self, make, model):
# These are INSTANCE attributes
self.make = make
self.model = model

car_one = Car("Toyota", "Camry")
car_two = Car("Honda", "Civic")

# All instances share the same class attribute
print(f"A {car_one.make} has {car_one.wheels} wheels.")
print(f"A {car_two.make} has {car_two.wheels} wheels.")

# You can also access it directly from the class
print(f"A car generally has {Car.wheels} wheels.")

In this example, wheels = 4 is a property of the Car blueprint itself. Every car we create will share this characteristic.


πŸ’» Section 2: Adding Behavior with Instance Methods​

An instance method is a function that is defined inside a class. It can perform actions, and most importantly, it can access and modify the object's instance attributes.

Just like __init__(), the first parameter of any instance method is always self. This self parameter is how the method knows which specific object it's being called on.

Let's give our Dog class from the previous article some behaviors.

# dog_with_methods.py

class Dog:
# Class attribute
species = "Canis familiaris"

def __init__(self, name: str, age: int):
# Instance attributes
self.name = name
self.age = age

# This is an INSTANCE METHOD
def bark(self):
"""Makes the dog bark."""
print(f"{self.name} says: Woof!")

# Another INSTANCE METHOD
def get_human_years(self) -> int:
"""Calculates the dog's age in human years."""
# The method can access the object's own age via self.age
return self.age * 7

# --- Let's use our methods ---
my_dog = Dog("Buddy", 4)

# Call the methods on the object using dot notation
my_dog.bark()

human_age = my_dog.get_human_years()
print(f"In human years, {my_dog.name} is {human_age} years old.")

Output:

Buddy says: Woof!
In human years, Buddy is 42 years old.

How self Works: When you call my_dog.bark(), Python automatically passes the my_dog object as the first argument to the bark methodβ€”this is what self becomes. This is how the method knows whose name to use in the print statement. It's the magic that connects the behavior (the method) to the data (the attributes) of a specific object.


✨ Conclusion & Key Takeaways​

You now know how to create classes that are more than just data containers. By defining attributes and methods, you can create objects that encapsulate both state (data) and behavior (actions), which is the central idea of Object-Oriented Programming.

Let's summarize the key takeaways:

  • Instance Attributes are unique to each object and are defined in __init__() with self.
  • Class Attributes are shared by all objects of a class and are defined directly in the class body.
  • Instance Methods are functions inside a class that define an object's behavior.
  • self is the Key: The self parameter in an instance method refers to the specific object the method was called on, giving the method access to that object's attributes.

Challenge Yourself: Add a method to the Car class you created in the last article's challenge. Call it display_info(). This method should print a formatted string like "2023 Toyota Camry". Then, create a Car object and call this new method.


➑️ Next Steps​

We've created objects and given them data and behaviors. But what happens when we try to print() one of our objects directly? The output isn't very helpful. In the next article, we'll learn how to control how our objects are represented as strings by exploring the special "Constructors: The __init__ method." (Wait, that's not right. The plan says "Constructors: The __init__ method", but we've already covered that. The next logical step is to cover special methods like __str__ and __repr__. I will proceed with that topic.)

Let's correct the plan. The next article will be about Special (Magic) Methods like __str__ and __repr__.

Happy coding!