Special methods - FluentPython

from collections import namedtuple

Card = namedtuple('Card', ['rank', 'suit'])

class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()
    
    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits
                                        for rank in self.ranks]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        '''
        delegates to [] operator, so supports slicing
        it also becomes iterable, reverse, sorted can be called upon
        '''
        return self._cards[position]

suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)

def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank)
    return rank_value * len(suit_values) + suit_values[card.suit]

if __name__ == '__main__':
    deck = FrenchDeck()
    print('Deck length', len(deck))
    print(deck[0])
    print(deck[-1])
    print(deck[12::13])

    for card in sorted(deck, key=spades_high):
        print(card)

Special methods are usually called by python interpreter.

If you need to invoke a special method like __len__, __getitem__, etc., it is better to call related builtin method like len, iter, str, etc. Built-in methods also provide other related services. It is always good to call built-in methods because they usually invoke Cpython code directly instead of method(special) call which are time consuming due to stack handling and many more related tasks join the picture.

Write a comment ...