Other Special Methods
A full list of special methods can be found here at the official python documentation website. There are quite a lot of special methods, so this last section will just go through the special methods that you might eventually use. These will not be on the quiz and are just here for those interested in them.
__contains__
The
__contains__
method is called when the in
operator is used. It should return True or False.Structure:
def __contains__(self, item) -> bool:
This method should return a bool representing whether or not the item is actually in the class.
Example:
class coordinateGrid: def __init__( self, x_start: int = 0, x_end: int = 10, y_start: int = 0, y_end: int = 10, ): """ Creates a list of coordinates similar to a coordinate grid. Each item in self.coordinates is a list representing one row in a coordinate grid. each item within that row is a point (tuple) of x, y ex: coordinateGrid(0, 1, -1, 1)'s coordinates would be [ [(0, 1), (1, 1)], [(0, 0), (1, 0)], [(0, -1), (1, -1)] ] Arguments: x_start, x_end, y_start, and y_end are all inclusive """ self.coordinates = [ [(x, y) for x in range(x_start, x_end + 1)] for y in range(y_end, y_start - 1, -1) ] def __contains__(self, item: tuple) -> bool: """ Checks to see if the provided tuple (or list) of length 2 (the tuple/list represents a point of x,y) is in self.coordinates. """ return True in [item in row for row in self.coordinates] grid1 = coordinateGrid(-1, 1, -1, 1) grid2 = coordinateGrid(-10, 10, -10, 10) point1 = (10, 10) print(point1 in grid1) # this will be False print(point1 in grid2) # this will be True
View code on GitHub
In this example, we created a class called coordinateGrid whose attribute self.coordinates was a 2D list of points/coordinates. Then, we instantiated coordinateGrid twice. grid1 was instantiated so that both its x and y values range from -1 to 1. grid2 was instantiated so that both its x and y values range from -10 to 10. Lastly, we created a coordinate (tuple) (10, 10) and checked whether it was in both coordinateGrid's. Since we used the
in
operator, __contains__ was called; it returned False for grid1 and True for grid2.__r...__
This is the workaround for doing (regular type) + (our defined class). Earlier in this chapter, we demonstrated how to do (our defined class) + (regular type) with the class Vector and
__add__
, __mul__
, and other mathematical methods. However, if we wanted to do int + Vector, we would use the special __r...__
methods__r...__
methods work just like the regular mathematical methods, but there is an r before the letters. For example, __add__
would be used for Vector + int, but __radd__
would be used for int + Vector. Also, __pow__
would be used for Vector ** int, but __rpow__
would be used for int ** VectorStructure:
def __radd__(self, other):
Depending on what you want to happen, you can return a value (so that print(int + Vector) would print a real number) or you could modify the class instance (so that (int + Vector) would change the Vector's values).
__len__
This allows you to use
len(your class)
.Structure:
def __len__(self) -> int:
This method should return an integer ≥ 0 to represent its length.
Example (building on-top of the coordinateGrid class)
# ... code from coordinateGrid class def __len__(self) -> bool: """ In this case, we're saying that the length of the coordinateGrid is its area. Thus, we do height * width height = len(self.coordinates) and width = len(self.coordinates[0]) (or any row's length) """ return len(self.coordinates) * len(self.coordinates[0]) grid1 = coordinateGrid(-1, 1, -1, 1) grid2 = coordinateGrid(-10, 10, -10, 10) print(len(grid1)) # 3 * 3 = 9 print(len(grid2)) # 21 * 21 = 441
View code on GitHub.
__getitem__
, __setitem__
These two special methods allow you to use your class like a dict or list (ie use
myclass[item/index]
)Structure:
def __getitem__(self, item):
(used when retrieving the value stored at myclass[item/index]
)def __setitem__(self, item, value):
(used when doing myclass[item/index] = ...
)Normally,
item
is either an integer or a string. Also note that, if the attribute isn't a valid attribute, you should do raise AttributeError
to let the user know that it is an invalid attribute.Example:
class bankAccount: def __init__(self, owner: str, balance: float): self.owner = owner self.balance = balance def __getitem__(self, item: str): if item == "owner": return self.owner elif item == "balance": return self.balance else: # if the attribute isn't a valid attribute, you should # raise an AttributeError raise AttributeError def __setitem__(self, item: str, value): if item == "owner": self.owner = value elif item == "balance": self.balance = value else: # if the attribute isn't a valid attribute, you should # raise an AttributeError raise AttributeError account = bankAccount("John", 100) print(account["owner"]) print(account["balance"]) account["balance"] = 200 print(account["balance"]) account['owner'] = "John Jr." print(account['owner'])
View code on GitHub.
In the above example, we have a class bankAccount with two attributes: owner and balance. Then, we have the
__getitem__
and __setitem__
methods that check if item
is a valid attribute (either owner or balance) and either return the corresponding value (in __getitem__
) or modify the corresponding value (in __setitem__
).__bool__
This allows you to use your class like a boolean. For example,
bool(myclass)
would give the value that __bool__
returns. Also, if myclass:
would be equivalent to if myclass.__bool__()
, meaning that the __bool__
method is called there to (same for elif).Structure:
def __bool__(self) -> bool:
Example: (building off of the previous bankAccount code)
# ... code from bankAccount class def __bool__(self): """ If we wanted the bank account to return True if the person is not bankrupt and False if they are bankrupt, we could do: """ return self.balance > 0 print(bool(account)) # this will print True (since the account has $200) if account: print("not bankrupt") # this will run
View code on GitHub.
Copyright © 2021 Code 4 Tomorrow. All rights reserved.
The code in this course is licensed under the MIT License.
If you would like to use content from any of our courses, you must obtain our explicit written permission and provide credit. Please contact classes@code4tomorrow.org for inquiries.