1. 程式人生 > >Python特殊方法的作用示例說明 具名元組的運用

Python特殊方法的作用示例說明 具名元組的運用

魔術方法(magic method)是特殊方法的暱稱,在Python中的特殊方法,一般都是使用諸如__xxx__(前後兩個下劃線,中間是方法名)的命名方式,在書裡有個名詞也可以形容它,比如__getitem__,叫做“雙下—getitem” (dunnder-getitem)

萬事開頭難
難以用概念去概括Python特殊方法的作用,最簡單的方法就是用例子說明。

很多人都會選擇使用Python作為快速開發工具,而特殊方法是屬於“快速”這個性質。

在Python中,要拿到一個集合的某個元素,可以使用對應的引索進行取值,比如list[key],這背後利用的是__getitem__方法,為了拿到my_list[key]的值,直譯器實際上會呼叫my_list.getitem

(key)。

Python也是面向物件程式語言,對於求一個集合的長度使用len(list)而不是list.len()會感覺有點奇怪,背後就是特殊方法的作用,呼叫了list.len()方法,和麵向物件完全符合,而且還起到簡化的作用,變得更加通俗易懂。

一個完整的例子
程式碼
import collections

Card = collections.namedtuple(‘Card’,[‘rank’, ‘suit’]) # 具名元組

class FrenchDeck:
ranks = [str(n) for n in range(2,11)] + list(‘JQKA’) # 牌數
suits = ‘spades hearts clubs diamonds’.split() # 牌色

def __init__(self):                            # 初始化(建構函式)
    self._cards = [Card(rank, suit) for suit in self.suits
                                    for rank in self.ranks]

def __len__(self):                             # 用len取長度的特殊方法
    return len(self._cards)

def __getitem__(self, position):               # 用引索取值的特殊方法
    return self._cards[position]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
執行

deck = FrenchDeck()
len(deck)
52

deck[0]
Card(rank=‘2’, suit=‘spades’)
1
2
3
4
5
隨機抽牌
那麼我們可以使用random模組裡面的一個方法隨機抽取一張牌

from random import choice
choice(deck)
Card(rank=‘2’, suit=‘clubs’)

choice(deck)
Card(rank=‘J’, suit=‘clubs’)
1
2
3
4
5
切片操作
既然我們實現了引索中括號[]操作,那麼我們也可以使用切片操作:

deck[:3]
[Card(rank=‘2’, suit=‘spades’), Card(rank=‘3’, suit=‘spades’),
Card(rank=‘4’, suit=‘spades’)]

deck[12::13]
[Card(rank=‘A’, suit=‘spades’), Card(rank=‘A’, suit=‘hearts’),
Card(rank=‘A’, suit=‘clubs’), Card(rank=‘A’, suit=‘diamonds’)]
1
2
3
4
5
6
迭代操作
另外,僅僅實現了__getitem__方法,那麼也變成了可迭代的了:

for card in deck: # 反向迭代也可以 reversed(deck)
print(card)

Card(rank=‘2’, suit=‘spades’)
Card(rank=‘3’, suit=‘spades’)
Card(rank=‘4’, suit=‘spades’)
···
Card(rank=‘Q’, suit=‘diamonds’)
Card(rank=‘K’, suit=‘diamonds’)
Card(rank=‘A’, suit=‘diamonds’)
1
2
3
4
5
6
7
8
9
10
in運算子
如果一個集合沒有實現__contains__方法,那麼in運算子會按順序做一次迭代搜尋。

Card(‘A’, ‘hearts’) in deck
True

Card(‘B’, ‘hearts’) in deck
False
1
2
3
4
排序
按照撲克牌的大小,2最小,A最大,同時要加上花色的大小判定,從大到小排序:黑桃、紅桃、梅花、方塊。

suit_values = dict(spades = 3, hearts = 2, clubs = 1, diamonds = 0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index (card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
1
2
3
4
執行

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

Card(rank=‘2’, suit=‘diamonds’)
Card(rank=‘2’, suit=‘clubs’)
Card(rank=‘2’, suit=‘hearts’)
Card(rank=‘2’, suit=‘spades’)
···
Card(rank=‘A’, suit=‘diamonds’)
Card(rank=‘A’, suit=‘clubs’)
Card(rank=‘A’, suit=‘hearts’)
Card(rank=‘A’, suit=‘spades’)