# Special Methods and Linked Lists¶

A list is a container for a sequence of values. Recall that “sequence” implies an order.

Each value in the list has something after it: the rest of the sequence. (Recursion!)

How do we know when we reach the end of our list? When the rest of the list is None.

```class LinkedList:
"""Implements our own recursive list data structure"""
__slots__ = ['_value', '_rest']

def __init__(self, value=None, rest=None):
self._value = value
self._rest = rest

```
```mylist = LinkedList(1)
```
```myList = LinkedList(5, LinkedList(3, LinkedList(11)))
```
```type(myList)
```
```__main__.LinkedList
```
```len(myList) # will this work?
```
```---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In , in <cell line: 1>()
----> 1 len(myList)

TypeError: object of type 'LinkedList' has no len()
```

## Special Methods¶

Suppose we want to support the following built-in functions: `len()`, `str()`, `contains()`, `add()`, `getitem()`, `setitem()`, and `eq()`. We might also want to add the method `append()` for consistency with regular lists.

```class LinkedList:
"""Implements our own recursive list data structure"""
__slots__ = ['_value', '_rest']

def __init__(self, value=None, rest=None):
self._value = value
self._rest = rest

# getters/setters
def getRest(self):
return self._rest

def getValue(self):
return self._value

def setValue(self, val):
self._value = val

def __strElements(self):
# helper function for __str__()
if self._rest is None:
return str(self._value)
else:
return str(self._value) + ", " + self._rest.__strElements()

def __str__(self):
return "[" + self.__strElements() + "]"

# repr() function calls __repr__() method
# return value should be a string that is a valid Python
# expression that can be used to recreate the LinkedList
def __repr__(self):

# len() function calls __len__() method
def __len__(self):
# base case: i'm the empty list
if self._rest is None and self._value is None:
return 0
# base case: i'm the last item
elif self._rest is None and self._value is not None:
return 1
#recursive case
else:
# same as return 1 + self._rest.__len__()
return 1 + len(self._rest)

# in operator calls __contains__() method
def __contains__(self, val):
if self._value == val:
return True
elif self._rest is None:
return False
else:
# same as calling self.__contains__(val)
return val in self._rest

# + operator calls __add__() method
# + operator returns a new instance of LinkedList
# other is another instance of LinkedList
# if we are the last item in the list
if self._rest is None:
# set _rest to other
self._rest = other
else:
# else, recurse until we reach the last item
return self

# [] list index notation calls __getitem__() method
# index specifies which item we want
def __getitem__(self, index):
# if index is 0, we found the item we need to return
if index == 0:
return self._value
else:
# else we recurse until index reaches 0
# remember that this implicitly calls __getitem__
return self._rest[index - 1]

# [] list index notation also calls __setitem__() method
# index specifies which item we want, val is new value
def __setitem__(self, index, val):
# if index is 0, we found the item we need to update
if index == 0:
self._value = val
else:
# else we recurse until index reaches 0
# remember that this implicitly calls __setitem__
self._rest[index - 1] = val

# == operator calls __eq__() method
# if we want to test two LinkedLists for equality, we test
# if all items are the same
def __eq__(self, other):
# If both lists are empty
if self._rest is None and other.getRest() is None:
return True

# If both lists are not empty, then value of current list elements
# must match, and same should be recursively true for
# rest of the list
elif self._rest is not None and other.getRest() is not None :
return self._value == other.getValue() and self._rest == other.getRest()

# If we reach here, then one of the lists is empty and other is not
return False

# append is not a special method, but it is a method
# that we know and love from the Python list class.
def append(self, val):
# if this is the last item
if self._rest is None:
else:
# else recurse until we find the end
self._rest.append(val)

```
```myList = LinkedList(4)
```
```print(myList)
```
```
```
```myList = LinkedList(5, myList)
```
```print(myList)
```
```[5, 4]
```
```myList = LinkedList(5, LinkedList(3, LinkedList(11)))
```
```print(myList) # testing __str__
```
```[5, 3, 11]
```
```myList  # testing __repr__
```
```LinkedList(5, LinkedList(3, LinkedList(11, None)))
```
```len(myList)  # testing __len__
```
```3
```
```print(myList)
```
```[5, 3, 11]
```
```1 in myList # testing __contains__
```
```False
```
```11 in myList
```
```True
```
```myList2 = LinkedList(4, LinkedList(6, LinkedList(10)))
```
```print(myList2)
```
```[4, 6, 10]
```
```print(myList)
```
```[5, 3, 11]
```
```myList3 = myList + myList2  # testing __add__
```
```print(myList3)
```
```[5, 3, 11, 4, 6, 10]
```
```len(myList3)
```
```6
```
```print(myList3)  # testing __getitem__
```
```5
```
```myList3=7   # testing __setitem__
```
```print(myList3)
```
```[7, 3, 11, 4, 6, 10]
```
```myList4 = LinkedList(5, LinkedList(3, LinkedList(11, LinkedList(13))))
```
```myList5 = LinkedList(5, LinkedList(3, LinkedList(11)))
```
```myList6 = LinkedList(5, LinkedList(3, LinkedList(11)))
```
```print(myList4)
print(myList5)
print(myList6)
```
```[5, 3, 11, 13]
[5, 3, 11]
[5, 3, 11]
```
```myList4 == myList5  # testing __eq__
```
```False
```
```myList5 == myList6
```
```True
```
```myList6.append(20)  # testing append
```
```myList = LinkedList(5, LinkedList(3, LinkedList(11)))
```
```for item in myList:
print(item)
```
```5
3
11
```
```---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In , in <cell line: 1>()
----> 1 for item in myList:
2     print(item)

Input In , in LinkedList.__getitem__(self, index)
76     return self._value
77 else:
78     # else we recurse until index reaches 0
79     # remember that this implicitly calls __getitem__
---> 80     return self._rest[index - 1]

Input In , in LinkedList.__getitem__(self, index)
76     return self._value
77 else:
78     # else we recurse until index reaches 0
79     # remember that this implicitly calls __getitem__
---> 80     return self._rest[index - 1]

Input In , in LinkedList.__getitem__(self, index)
76     return self._value
77 else:
78     # else we recurse until index reaches 0
79     # remember that this implicitly calls __getitem__
---> 80     return self._rest[index - 1]

TypeError: 'NoneType' object is not subscriptable
```