《流暢的python》一書是python入門之后進階的一本好書险胰。它不是一本完備的python手冊弦悉,而是強調(diào)python作為編程語言獨有的特性夕凝。這些特性或者是python獨有的噪沙,或者是其它編程語言里很少見的昂芜。在接下來的一段時間别伏,我會整理這本書的筆記蹄衷,大家相互學習,共同進步厘肮。
一愧口、pythonic風格的代碼是什么樣的?
最簡單的兩個變量a,b交換value:
其它語言大部分需要用到臨時變量,例如:
$a = 100;
$b = 200;
$c = $a;
$b = $a;
$a = $c;
echo $a,$b;#200100
$a 與$b交換值类茂,需要借助臨時$c來實現(xiàn)耍属。如果是python呢?
a,b = 100,200
a,b = b,a
print(a,b)#200 100
對巩检,這就是pythonic的代碼厚骗,是不是很簡單易讀?來個更直觀的栗子:
定義一副撲克牌
import collections
Card = collections.namedtuple('Card',['rank','suit'])
class FrenchDeck:
rank = [str(i) for i in range(2,11)]+'JQKA'
suit = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank,suit) for suit in self.suit for card in self.rank]
def __len__(self):
return len(self._cards)
def __getitem__(self,position):
return self._cards[position]
短短十來行代碼就定義 了一副撲克牌兢哭,是不是覺得很輕松呢领舰?
注意:collections.namedtuple()方法用以構(gòu)建只有少數(shù)屬性沒有方法的對象,例如數(shù)據(jù)庫條目。在python2中定義一個類需要顯式的繼承object提揍,定義類名時需要FrenchDeck(object)繼承的父類啤月,python3則默認繼承object不用再寫object了。
python定義列表的特別之處莫過于它的列表生成式了劳跃,簡單明了谎仲, 敲起來也方便。其中:
rank = [str(i) for i in range(2,11)]+'JQKA'
使用列表生成式定義了撲克牌中的2~A
suit = 'spades diamonds clubs hearts'.split()
定義了撲克牌的四種花色
self._cards = [Card(rank,suit) for suit in self.suit for card in self.rank]
再次使用列表生成式將花色與點數(shù)組合起來刨仑。其實三行代碼已經(jīng)將撲克牌定義完了郑诺,列表生成式的優(yōu)點就在于可以用極短的代碼,完成列表的創(chuàng)建杉武。假設使用迭代的方式定義這副撲克牌辙诞,很顯然,代碼就不會是三行了轻抱。
好了飞涂,既然有了一副撲克牌,那我們就要來賭點大的了祈搜。
#1.紙牌數(shù)量
#因為我們重新定義了特殊方法__len__,當我們需要紙牌數(shù)量的時候直接使用len()方法就可以较店。
#特殊方法的存在是給python解釋器使用的,你不需要調(diào)用它們容燕,也就是說沒有my_obj.__len__()這種寫法梁呈,
#而應該使用len(my_obj),在執(zhí)行l(wèi)en(my_obj)的時候,如果my_obj是你自己定義的對象蘸秘,那么python會去
#調(diào)用由你實現(xiàn)的__len__方法
deck = FrenchDeck()
print(len(deck))#52
#抽取第一張或者最后一張
deck[0]或deck[-1]
#隨機抽取一張
from random import choice
choice(deck)
#由于__getitem__方法把[]操作交給了self._cards列表官卡,所以deck支持切片和迭代操作
#取出四張A(切片)
deck[12::13]
#迭代
for card in deck:
print(card)
#反向迭代
for card in reversed(deck):
print(card)
#排序(升序)
suit_value = dict(spades=3,hearts=2,diamonds=1,clubs=0)
def spades_high(card):
rank_value = FrenchDeck.rank.index(card.rank)
return rank_value * len(suit_value) + suit_value[card.suit]
for card in sorted(deck,key=spades_high):
print(card)
二、python中的特殊方法
如__getitem__這些帶雙下劃線的方法醋虏,我們稱之為特殊方法寻咒,特殊方法的存在是為了被解釋器調(diào)用的,你自己并不需要調(diào)用它們颈嚼。很多時候仔涩,特殊方法的調(diào)用是隱式的,例如循環(huán)語句粘舟,for i in x:這個語句熔脂,背后其實使用的是iter(x),而這個函數(shù)的背后是x.__iter__()方法,當然柑肴,前提是__iter__這個方法被實現(xiàn)了霞揉。
通常來說,代碼無需直接使用特殊方法晰骑。除非有大量的元編程存在适秩,直接調(diào)用特殊方法的頻率應該遠遠低于你去實現(xiàn)它們的次數(shù)绊序。唯一例外的可能是__init__方法,你的代碼里可能經(jīng)常會用到它秽荞,目的是在你自己的子類的__init__方法中調(diào)用超類的構(gòu)造器骤公。
此外,不要自己想當然的隨意添加特殊方法扬跋,比如__foo__之類阶捆。因為雖然現(xiàn)在這個名字沒有被python內(nèi)部使用,以后就不一定了钦听。