6.2 Attributes and Methods in Python

In Python's Object-Oriented Programming (OOP), attributes and methods are central concepts that define the properties and behaviors of objects. Attributes represent the state (data) of an object, while methods define the behavior (functions) that can be performed on the object. Together, they form the building blocks of object-oriented design.

In this section, we’ll explore the different types of attributes and methods, how to work with them, and best practices for using them in classes.


6.2.1 What are Attributes?

Attributes are variables that belong to a class or an object. They are used to store data related to the object. Attributes can be either instance attributes (specific to an object) or class attributes (shared among all instances of the class).


6.2.2 Instance Attributes

Instance attributes are specific to each object (instance) of a class. They are defined inside the __init__() method (constructor) and are unique for each object. Every time you create a new instance, its instance attributes are initialized with values.

Example:

class Person:
    def __init__(self, name, age):
        # Instance attributes
        self.name = name
        self.age = age

# Creating two objects with different instance attribute values
person1 = Person("Alice", 30)
person2 = Person("Bob", 25)

# Accessing instance attributes
print(person1.name)  # Output: Alice
print(person2.age)   # Output: 25

In this example:

  • self.name and self.age are instance attributes.
  • Each object (person1 and person2) has its own values for these attributes, which are independent of each other.

6.2.3 Class Attributes

Class attributes are variables that are shared across all instances of a class. They are defined directly in the class body, outside of any methods. Unlike instance attributes, class attributes have the same value for every object unless explicitly overridden.

Example:

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

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

# Creating two objects
dog1 = Dog("Buddy", 5)
dog2 = Dog("Bella", 3)

# Accessing class attribute (shared across all objects)
print(dog1.species)  # Output: Canis lupus familiaris
print(dog2.species)  # Output: Canis lupus familiaris

# Accessing instance attributes (specific to each object)
print(dog1.name)  # Output: Buddy
print(dog2.age)   # Output: 3

In this example:

  • species is a class attribute and is the same for all instances of the Dog class.
  • name and age are instance attributes and vary from one object to another.

6.2.4 Modifying Attributes

You can modify both instance and class attributes after an object is created.

Modifying Instance Attributes:

dog1 = Dog("Buddy", 5)
print(dog1.name)  # Output: Buddy

# Modifying the instance attribute
dog1.name = "Max"
print(dog1.name)  # Output: Max

In this case, the instance attribute name is modified directly on the object dog1.

Modifying Class Attributes:

print(Dog.species)  # Output: Canis lupus familiaris

# Modifying the class attribute
Dog.species = "Canis familiaris"
print(Dog.species)  # Output: Canis familiaris

# The change affects all instances
print(dog1.species)  # Output: Canis familiaris
print(dog2.species)  # Output: Canis familiaris

When you modify a class attribute, the change applies to all instances of the class unless they have explicitly overridden the attribute.


6.2.5 What are Methods?

Methods are functions defined inside a class that describe the behaviors of the objects. Methods operate on the instance or class attributes and perform actions or calculations using the object’s data.


6.2.6 Instance Methods

Instance methods are functions that operate on instance attributes and require the self parameter to access the object’s state. They are the most common type of methods in a class.

Example:

class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    # Instance method
    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * (self.length + self.width)

Using Instance Methods:

rect = Rectangle(10, 5)
print(f"Area: {rect.area()}")          # Output: Area: 50
print(f"Perimeter: {rect.perimeter()}")  # Output: Perimeter: 30

In this example:

  • The methods area() and perimeter() are instance methods that operate on the instance attributes length and width.
  • The self parameter allows the methods to access the specific attributes of the instance (rect in this case).

6.2.7 Class Methods

Class methods are methods that operate on class attributes rather than instance attributes. They are defined using the @classmethod decorator and take cls as the first parameter, which refers to the class itself.

Example:

class Circle:
    pi = 3.14159  # Class attribute

    def __init__(self, radius):
        self.radius = radius  # Instance attribute

    # Class method
    @classmethod
    def set_pi(cls, value):
        cls.pi = value

Using Class Methods:

# Accessing class attribute before modification
print(Circle.pi)  # Output: 3.14159

# Modifying the class attribute using a class method
Circle.set_pi(3.14)
print(Circle.pi)  # Output: 3.14

In this example:

  • The set_pi() method is a class method that modifies the class attribute pi.
  • The @classmethod decorator allows the method to access and modify class-level data.

6.2.8 Static Methods

Static methods are methods that do not operate on instance or class attributes. They are used when you need a function inside a class but don’t need access to any data from the instance or the class. Static methods are defined using the @staticmethod decorator.

Example:

class MathOperations:
    @staticmethod
    def add(a, b):
        return a + b

    @staticmethod
    def subtract(a, b):
        return a - b

Using Static Methods:

print(MathOperations.add(10, 5))      # Output: 15
print(MathOperations.subtract(10, 5))  # Output: 5

In this example:

  • The methods add() and subtract() are static methods that perform operations without accessing any instance or class attributes.

6.2.9 The self and cls Parameters

  • self: Refers to the instance of the class and is used to access instance attributes and methods. It must be the first parameter in any instance method.
  • cls: Refers to the class itself and is used in class methods to access class attributes. It must be the first parameter in any class method.

Example of self and cls:

class Example:
    class_attr = "I am a class attribute"

    def __init__(self, value):
        self.instance_attr = value

    def show_instance(self):
        print(f"Instance attribute: {self.instance_attr}")

    @classmethod
    def show_class(cls):
        print(f"Class attribute: {cls.class_attr}")

In this example:

  • self.instance_attr is an instance attribute, accessed via the self parameter in the show_instance() method.
  • cls.class_attr is a class attribute, accessed via the cls parameter in the show_class() method.

6.2.10 Access Control: Public and Private Attributes

By convention, Python uses underscores (_) to indicate the intended visibility of attributes and methods.

  • Public attributes and methods: Can be accessed from anywhere.
  • Private attributes and methods: Indicated by a double underscore (__), and are intended to be accessed only within the class.

Example:

class Employee:
    def __init__(self, name, salary):
        self.name = name        # Public attribute
        self.__salary = salary  # Private attribute

    def get_salary(self):
        return self.__salary

    def __calculate_bonus(self):
        return self.__salary * 0.1  # Private method

Accessing Attributes:

emp = Employee("Alice", 50000

)
print(emp.name)         # Output: Alice
# print(emp.__salary)   # Raises AttributeError, as __salary is private

# Accessing private attribute through a public method
print(emp.get_salary())  # Output: 50000

In this example:

  • name is a public attribute that can be accessed directly.
  • __salary is a private attribute, so it cannot be accessed directly from outside the class.

6.2.11 Summary

  • Attributes are variables that store data for objects. They can be instance attributes (specific to each object) or class attributes (shared by all instances).
  • Methods are functions defined within a class that describe the behaviors of the objects. There are three types of methods:
    • Instance methods: Operate on instance attributes and require the self parameter.
    • Class methods: Operate on class attributes and require the cls parameter. Defined with the @classmethod decorator.
    • Static methods: Do not operate on instance or class attributes. Defined with the @staticmethod decorator.
  • self refers to the current object instance, while cls refers to the class itself.
  • Attributes can be public or private, with private attributes being accessible only within the class.

Understanding attributes and methods is key to building flexible and reusable object-oriented code. With these concepts, you can create complex and well-structured Python applications.