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:

  1. 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.

  2. 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__.

  3. 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.

  4. 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:

  1. Fluent Python by Luciano Ramalho, Andao, and Ke Wu.

  2. CSDN: Classification and summary of special methods in Python