Python Note 001- Special methods of classes
Here are my personal notes after learning Fluent Python, which I now share with you in the hope of helping Python learners.
First published in: wechat public number: Science and Technology Old Ding Ge, ID: TechDing, please pay attention.
This article mainly points out:
-
Class special methods (usually preceded by two underscores, such as __len__ and __getitem__) exist to be called by the Python interpreter, not the objects of the class.
-
The core features of the Python language, such as iteration and slicing, are generally not available to custom classes, but they can be implemented by overriding special methods such as __len__ and __getitem__ in custom classes. When len() is called, the Python interpreter actually calls __len__ from a custom class, whereas when an object is sliced to get elements, or sorted, the Python interpreter calls __getitem__.
-
Overwriting __getitem__ in a custom class yields at least 1. Slices of class objects and elements, 2. Iterating the class objects, either in order or in reverse order; 3. Reordering the class objects; 4. Random sampling of class objects and other functions.
-
There are as many as 100 kinds of special methods of class, as an example, here only summarized the copying methods of addition, subtraction, multiplication and division, etc., and all the special methods are organized into related tables, convenient for the subsequent copying of some special methods as a reference.
1. Special method example
These special methods look odd because they remind the user not to call them lightly, since they are basically specific to the Python interpreter.
So let’s say we create a whole deck of cards, and it has a property called _cards, and this is a list of 52 Card objects. After overwriting the __len__ and __getitem__ methods, you can directly get the total length of the _cards attribute and sort and slice it to get some cards.
from collections import namedtuple
Card=namedtuple('Card'['rank'.'suit']) # Single card class
class FrenchDeck: A pack of cards containing 4 suits and 13 numbers each
ranks = [str(n) for n in range(2.11)] + list('JQKA') # 13 numbers
suits = 'spades diamonds clubs hearts'.split() # Four different suits: spades, diamonds, clubs, hearts
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
The # _cards attribute is a collection of all cards, a list of 52 cards in 4 suits
def __len__(self):
# FrechDeck class special method: count all cards, i.e. 52
return len(self._cards)
def __getitem__(self, position):
# special method of class FrechDeck: get position from 52 cards
return self._cards[position]
Copy the code
After building a deck of cards, we want to know how many cards are in it, or what the first, 10th, and last card are:
## Get how many cards in your deck by len()
deck=FrenchDeck()
print(len(deck)) # 52
Get a card at a position by slicing
print(deck[0]) # Card(rank='2', suit='spades')
print(deck[10]) # Card(rank='Q', suit='spades')
print(deck[- 1]) # Card(rank='A', suit='hearts')
Copy the code
TypeError: Object of type ‘FrenchDeck’ has no len().
Similarly, if the __getitem__ method is not overridden, deck[0] will report an error: TypeError: ‘FrenchDeck’ object does not support indexing
You can index your deck to get the cards at A certain position, so you can slice it to get A lot of cards that meet certain conditions, like the last three cards and the cards with all ACES.
print(deck[- 3:)Get the last three cards
print(deck[12: :13]) Get all ace cards, spaced slices
Copy the code
Similarly, once the __getitem__ method is overwritten, you can iterate over the Deck object, either sequentially or in reverse.
# Sequential iteration
for card in deck[:10]: Print only the top 10 cards
print(card)
# Reverse iteration
for card in reversed(deck[-10:]): Print only the last 10 cards
print(card)
Copy the code
You can also determine whether a card exists in the deck:
Determine if a card exists in the deck:
print(Card('Q'.'hearts') in deck) # True
print(Card('Z'.'clubs') in deck) # False
Copy the code
With the __getitem__ method, we can sort all cards, here we sort: 2 of clubs minimum, 2 of diamonds second, 2 of hearts, 2 of spades, 3 of clubs.. This method returns an integer representing the size of each card, so the smallest two of clubs is 0, and the largest ace of spades is 51.
Reorder all cards using a custom method
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) # Convert suits to numbers
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank) Get the number of a card
return rank_value * len(suit_values) + suit_values[card.suit]
Return the number and suit of a card as an integer
for card in sorted(deck, key=spades_high):
Select * from spades_high; select * from spades_high
print(card)
Copy the code
To summarize, custom classes override the __getitem__ method to provide a variety of functions that didn’t exist before: slicing, indexing, determining whether an object exists in a list of class objects, iterating over and sorting class objects.
2. Use of special methods
For custom types, using these special methods makes them behave like some of Python’s core functions. When you operate on these custom types, such as len(deck), the Python interpreter looks for the deck class’s __len__ method.
For Python’s built-in types, such as list, STR, tuple, etc., the Python interpreter takes a shortcut and returns the Ob_size property of PyVarObject, a variable length C construct, much faster than calling __len__.
Your own use of these special methods will be minimal, since they are called automatically by the Python interpreter, with the exception of the __init__ method at class definition.
2.1 User-defined functions of addition, subtraction, multiplication and division
class Person:
def __init__(self,name,age,score):
self.name=name
self.age=age
self.score=score
def __add__(self,other):
# Just add the scores
return self.score+other.score
def __sub__(self,other):
# Here the scores will be subtracted
return self.score-other.score
def __mul__(self,other):
Multiply the ages of both here
return self.age*other.age
def __truediv__(self,other):
Divide the scores of the two
return self.score/other.score
Copy the code
This custom Person class duplicates the addition, subtraction, multiplication, and division methods to perform arithmetic operations on attributes as needed, using the symbols +,-,*,/, etc., for example:
P1=Person('Jack'.20.90)
P2=Person('Rose'.18.60)
print(P1+P2) # 150
print(P1-P2) # 30
print(P1*P2) # 360
print(P1/P2) # 1.5
Copy the code
2.2 Customize the form of print
There is also a special function that is very common: __repr__, which determines what the result should look like when print is called directly.
class Person:
def __init__(self,name,age,score):
self.name=name
self.age=age
self.score=score
def __repr__(self):
return 'Person(name={},age={},score={})'.format(self.name,self.age,self.score)
P1=Person('Jack'.20.90)
print(P1) # Person(name=Jack,age=20,score=90)
Copy the code
If __repr__ is not overwritten, print(P1) will get the memory address information, the human eye can not determine the specific content, after overwritten, we can directly print the form we want.
3. Summary of special methods
There are nearly a hundred special methods built into Python, many of which implement arithmetic operations, bit operations, and comparisons. Here’s what they mean:
The following is summarized in: CSDN: Classification and summary of special methods in Python
So, if a custom class wants to do something, you can refer to the table above to do it one by one.
First published in: wechat public number: Science and Technology Old Ding Ge, ID: TechDing, please pay attention.
All the code for this article has been uploaded to my Github
References:
-
Fluent Python by Luciano Ramalho, Andao, and Ke Wu.
-
CSDN: Classification and summary of special methods in Python