# How to implement __getitem__, __setitem__, and __delitem__ in Python

Python has numerous collections of dunder methods(which start with double underscores and end with double underscores) to perform various tasks. The most commonly used dunder method is `__init__` which is used in Python classes to create and initialize objects.

In this article, we'll see the usage and implementation of the underutilized dunder methods such as `__getitem__`, `__setitem__`, and `__delitem__` in Python.

# **\_\_getitem**\_\_

The name **getitem** depicts that this method is used to access the items from the list, dictionary and array.

If we have a list of names and want to access the item on the third index, we would use `name_list[3]`, which will return the name from the list on the third index. When the `name_list[3]` is evaluated, Python internally calls `__getitem__` on the data (`name_list.__getitem__(3)`).

The following example shows us the practical demonstration of the above theory.

```python
# List of names
my_list = ['Sachin', 'Rishu', 'Yashwant', 'Abhishek']

# Accessing items using bracket notation
print('Accessed items using the bracket notation')
print(my_list[0])
print(my_list[2], "\n")

# Accessing items using __getitem__
print('Accessed items using the __getitem__')
print(my_list.__getitem__(1))
print(my_list.__getitem__(3))
```

We used the commonly used bracket notation to access the items from the `my_list` at the `0th` and `2nd` index and then to access the items at the `1st` and `3rd` index, we implemented the `__getitem__` method.

```bash
Accessed items using the bracket notation
Sachin
Yashwant 

Accessed items using the __getitem__
Rishu
Abhishek
```

### Syntax

`__getitem__(self, key)`

The \_\_**getitem**\_\_ is used to evaluate the value of `self[key]` by the object or instance of the class. Just like we saw earlier, `object[key]` is equivalent to `object.__getitem__(key)`.

`self` - object or instance of the class

`key` - value we want to access

### \_\_getitem\_\_ in Python classes

```python
# Creating a class
class Products:
    def __getitem__(self, items):
        print(f'Item: {items}')


item = Products()
item['RAM', 'ROM']
item[{'Storage': 'SSD'}]
item['Graphic Card']
```

We created a Python class named `Products` and then defined the `__getitem__` method to print the `items`. Then we created an instance of the class called `item` and then passed the values.

```bash
Item: ('RAM', 'ROM')
Item: {'Storage': 'SSD'}
Item: Graphic Card
```

These values are of various data types and were actually parsed, for example, `item['RAM', 'ROM']` was parsed as a tuple and this expression was evaluated by the interpreter as `item.__getitem__(('RAM', 'ROM'))`.

Checking the type of the item along with the items.

```python
import math
# Creating a class
class Products:
    # Printing the types of item along with items
    def __getitem__(self, items):
        print(f'Item: {items}. Type: {type(items)}')


item = Products()
item['RAM', 'ROM']
item[{'Storage': 'SSD'}]
item['Graphic Card']
item[math]
item[89]
```

**Output**

```bash
Item: ('RAM', 'ROM'). Type: <class 'tuple'>
Item: {'Storage': 'SSD'}. Type: <class 'dict'>
Item: Graphic Card. Type: <class 'str'>
Item: <module 'math' (built-in)>. Type: <class 'module'>
Item: 89. Type: <class 'int'>
```

### Example

In the following example, we created a class called `Products`, an `__init__` that takes `items` and a `price`, and a `__getitem__` that prints the value and type of the value passed inside the indexer.

Then we instantiated the class `Products` and passed the arguments `'Pen'` and `10` to it, which we saved inside the `obj`. Then, using the instance `obj`, we attempted to obtain the values by accessing the parameters `items` and `price`.

```python
# Creating a class
class Products:
    # Creating a __init__ function
    def __init__(self, items, price):
        self.items = items
        self.price = price
    
    def __getitem__(self, value):
        print(value, type(value))

# Creating instance of the class and passing the values
obj = Products('Pen',10)
# Accessing the values
obj[obj.items]
obj[obj.price]
```

**Output**

```bash
Pen <class 'str'>
10 <class 'int'>
```

# \_\_setitem\_\_

The `__setitem__` is used to assign the values to the item. When we assign or set a value to an item in a list, array, or dictionary, this method is called internally.

Here's an example in which we created a list of names, and attempted to modify the list by changing the name at the first index (`my list[1] = 'Yogesh'`), and then printed the updated list.

To demonstrate what the interpreter does internally, we modified the list with the help of `__setitem__`.

```python
# List of names
my_list = ['Sachin', 'Rishu', 'Yashwant', 'Abhishek']

# Assigning other name at the index value 1
my_list[1] = 'Yogesh'
print(my_list)

print('-'*20)

# What interpreter does internally
my_list.__setitem__(2, 'Rishu')
print(my_list)
```

When we run the above code, we'll get the following output.

```bash
['Sachin', 'Yogesh', 'Yashwant', 'Abhishek']
--------------------
['Sachin', 'Yogesh', 'Rishu', 'Abhishek']
```

### Syntax

`__setitem__(self, key, value)`

The `__setitem__` assigns a value to the key. If we call `self[key] = value`, then it will be evaluated as `self.__setitem__(key, value)`.

`self` - object or instance of the class

`key` - the item that will be replaced

`value` - `key` will be replaced by this value

### \_\_setitem\_\_ in Python classes

The following example demonstrates the implementation of the `__setitem__` method in a Python class.

```python
# Creating a class
class Roles:
    # Defining __init__ method
    def __init__(self, role, name):
        # Creating a dictionary with key-value pair
        self.detail = {
            'name': name,
            'role': role
        }

    # Defining __getitem__ method
    def __getitem__(self, key):
        return self.detail[key]

    # Function to get the role and name
    def getrole(self):
        return self.__getitem__('role'), self.__getitem__('name')
    
    # Defining __setitem__ method
    def __setitem__(self, key, value):
        self.detail[key] = value

    # Function to set the role and name
    def setrole(self, role, name):
        print(f'{role} role has been assigned to {name}.')
        return self.__setitem__('role', role), self.__setitem__('name', name)

# Instantiating the class with required args
data = Roles('Python dev', 'Sachin')
# Printing the role with name
print(data.getrole())

# Setting the role for other guys
data.setrole('C++ dev', 'Rishu')
# Printing the assigned role with name
print(data.getrole())
# Setting the role for other guys
data.setrole('PHP dev', 'Yashwant')
# Printing the assigned role with name
print(data.getrole())
```

We created a `Roles` class and a `__init__` function, passing the `role` and `name` parameters and storing them in a dictionary.

Then we defined the `__getitem__` method, which returns the key's value, and the `getrole()` function, which accesses the value passed to the key `name` and `role`.

Similarly, we defined the `__setitem__` method, which assigns a value to the key, and we created the `setrole()` function, which assigns the specified values to the key `role` and `name`.

The class `Roles('Python dev,' 'Sachin')` was then instantiated with required arguments and stored inside the `data` object. We printed the `getrole()` function to get the **role** and **name**, then we called the `setrole()` function twice, passing it the various **roles** and **names**, and printing the `getrole()` function for each `setrole()` function we defined.

```bash
('Python dev', 'Sachin')
C++ dev role has been assigned to Rishu.
('C++ dev', 'Rishu')
PHP dev role has been assigned to Yashwant.
('PHP dev', 'Yashwant')
```

We got the values passed as an argument to the class but after it, we set the different roles and names and got the output we expected.

# \_\_delitem\_\_

The `__delitem__` method deletes the items in the list, dictionary, or array. The item can also be deleted using the `del` keyword.

```python
# List of names
my_list = ['Sachin', 'Rishu', 'Yashwant', 'Abhishek']

# Deleting the first item of the list
del my_list[0]
print(my_list)

# Deleting the item using __delitem__
my_list.__delitem__(1)
print(my_list)

----------
['Rishu', 'Yashwant', 'Abhishek']
['Rishu', 'Abhishek']
```

In the above code, we specified the `del` keyword and then specified the index number of the item to be deleted from `my_list`.

So, when we call `del my_list[0]` which is equivalent to `del self[key]`, Python will call `my_list.__delitem__(0)` which is equivalent to `self.__delitem__(key)`.

### **\_\_**delitem\_\_ in Python class

```python
class Friends:
    def __init__(self, name1, name2, name3, name4):
        self.n = {
            'name1': name1,
            'name2': name2,
            'name3': name3,
            'name4': name4
        }

    # Function for deleting the entry
    def delname(self, key):
        self.n.__delitem__(key)

    # Function for adding/modifying the entry
    def setname(self, key, value):
        self.n[key] = value


friend = Friends('Sachin', 'Rishu', 'Yashwant', 'Abhishek')
print(friend.n, "\n")

# Deleting an entry
friend.delname('name3')
print('After deleting the name3 entry')
print(friend.n, "\n")

# Modifying an entry
friend.setname('name2', 'Yogesh')
print('name2 entry modified')
print(friend.n, "\n")

# Deleting an entry
friend.delname('name2')
print('After deleting the name2 entry')
print(friend.n)
```

We defined the `delname` function in the preceding code, which takes a `key` and deletes that entry from the dictionary created inside the `__init__` function, as well as the `setname` function, which modifies/adds the entry to the dictionary.

Then we instantiated the `Friends` class, passed in the necessary arguments, and stored them in an instance called `friends`.

Then we used the `delname` function to remove an entry with the key `name3` before printing the updated dictionary. In the following block, we modified the entry with the key `name2` to demonstrate the functionality of `setname` function and printed the modified dictionary, then we deleted the entry with the key `name2` and printed the updated dictionary.

```bash
{'name1': 'Sachin', 'name2': 'Rishu', 'name3': 'Yashwant', 'name4': 'Abhishek'} 

After deleting the name3 entry
{'name1': 'Sachin', 'name2': 'Rishu', 'name4': 'Abhishek'} 

name2 entry modified
{'name1': 'Sachin', 'name2': 'Yogesh', 'name4': 'Abhishek'} 

After deleting the name2 entry
{'name1': 'Sachin', 'name4': 'Abhishek'}
```

# Conclusion

We learned about the `__getitem__`, `__setitem__`, and `__delitem__` methods in this article. We can compare `__getitem__` to a getter function because it retrieves the value of the attribute, `__setitem__` to a setter function because it sets the value of the attribute, and `__delitem__` to a deleter function because it deletes the item.

We implemented these methods within Python classes in order to better understand how they work.

We've seen code examples that show what Python does internally when we access, set, and delete values.

---

🏆**Other articles you might be interested in if you liked this one**

✅[How to use and implement the \_\_init\_\_ and \_\_call\_\_ in Python](https://geekpython.in/init-and-call-method).

✅[Types of class inheritance in Python with examples](https://geekpython.in/class-inheritance-in-python).

✅[How underscores modify accessing the attributes and methods in Python](https://geekpython.in/access-modifiers-in-python).

✅[Create and manipulate the temporary file in Python](https://geekpython.in/tempfile-in-python).

✅[Display the static and dynamic images on the frontend using FastAPI](https://geekpython.in/displaying-images-on-the-frontend-using-fastapi).

✅[Python one-liners to boost your code](https://geekpython.in/one-liners-in-python).

✅[Perform a parallel iteration over multiple iterables using zip() function in Python](https://geekpython.in/zip-function-in-python-usage-and-examples-with-code).

---

**That's all for now**

**Keep Coding✌✌**
