1.現在在看《流暢的Python》這本書,看了三頁就發現,這本書果然不是讓新手來入門的,一些很常見的知識點能被這個作者玩出花來,
唉,我就在想,下面要分析的這些的代碼,就算我費勁巴拉的看懂了,又有什么用呢,我其實不想靠着技術吃飯,但是現在在這個崗位上,
就得在其位謀其職,悲哀。我在敲代碼方面也沒什么天賦,也沒什么熱情,老話說得好,‘女怕嫁錯郎,男怕入錯行’,
所以我得從IT行業抽出身來。anyway,進入正題。
2.python解釋器碰到特殊的句法時,會使用特殊方法去激活一些基本的對象操作,這些特殊方法的名字以兩個下划線開頭,
以兩個下划線結尾(例如__getitem__)。比如obj[key]的背后就是__getitem__方法,為了求得my_collection[key]的值,解釋器實際上會調用my_collection.__getitem__(key),雙下划線這種特殊方法也叫雙下方法(dunder method).
import collections
Card = collections.namedtuple('Card',['rank','suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2,11)] + list('JQKA')
# ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
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):
# print("用的是我寫的lenth")
# 如果不寫這個方法,用len(deck)時會報錯:TypeError: object of type 'FrenchDeck' has no len()
return len(self._cards)
def __getitem__(self, position):
return self._cards[position]
>>> beer_card = Card('7','hearts')
>>> beer_card
Card(rank='7', suit='hearts')
這張牌就是紅心7
FrenchDeck類中的self._cards生成了一個有52張'牌'的列表
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), ...共52個]
suits = ['spades', 'diamonds', 'clubs', 'hearts']
namedtuple的作用:
>>> beer_card = Card('7','hearts')
>>> beer_card
Card(rank='7', suit='hearts')
FrenchDeck類支持的方法:
>>> deck = FrenchDeck()
>>> len(deck)
52
>>> from random import choice
>>> choice(deck)
支持分片:只看牌面是A的牌--先抽出索引是12的那張牌,然后每隔13張拿一張
>>> deck[12::13]
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'),
Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
這個我覺得作者的用法很好
僅僅用__getitem__方法,使這一摞牌變成可迭代
>>> for card in deck:
... print(card)
反向迭代
>>> for card in reversed(deck):
... print(card)
一個集合類型如果沒有實現__contains__方法,in運算符就會按順序做一次迭代搜索
>>> Card(rank='A', suit='spades') in deck
True
下面這段就厲害了,弄得我眼黑頭暈的,弄了一早上才搞明白,怎么對這些撲克牌進行排序?
首先你會想到sorted,但我連它的key參數都不會用,何談去排序這些撲克。sorted用法:
sorted最簡單用法是對元素全部是數字的列表排序,另一種用法是對元素是元組或字典的列表排序
用到的參數是key,比如:對學生的分數進行排序:
list1 = [('david', 90), ('mary',90), ('sara',80),('lily',95)]
sorted(list1, key=lambda x: x[0]) # 按照元組中第一個元素排序
sorted(list1, key=lambda x: x[1]) # 按照元組中第二個元素排序
array = [{"age":20,"name":"a"},{"age":25,"name":"b"},{"age":10,"name":"c"}]
array1 = sorted(array,key=lambda x:x["age"]) # 按照年齡排序
下面要講的例子,先拋個磚:
1.需求:將列表中的元素按照絕對值大小進行升序排列
list1 = [3,5,-4,-1,0,-2,-6]
sorted(list1, key=lambda x: abs(x))
當然,也可以如下:
list1 = [3,5,-4,-1,0,-2,-6]
def get_abs(x):
return abs(x)
sorted(list1,key=get_abs)
只不過這種方式的代碼看起來不夠Pythonic
2、應用在閉包中
def get_y(a,b):
return lambda x:ax+b
y1 = get_y(1,1)
y1(1) # 結果為2
當然,也可以用常規函數實現閉包,如下:
def get_y(a,b):
def func(x):
return ax+b
return func
y1 = get_y(1,1)
y1(1) # 結果為2
只不過這種方式顯得有點啰嗦。
那么是不是任何情況下lambda函數都要比常規函數更清晰明了呢?
Python之禪中有這么一句話:Explicit is better than implicit(明了勝於晦澀),就是說那種方式更清晰就用哪一種方式,不要盲目的都使用lambda表達式。
撲克牌排序代碼:
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
# {'clubs': 0, 'diamonds': 1, 'spades': 3, 'hearts': 2}
def spades_high(card):
rank_values = FrenchDeck.ranks.index(card.rank)
return rank_values * len(suit_values) + suit_values[card.suit]
for card in sorted(deck,key=spades_high):
print(card)
一、這段代碼我看了很長時間,這本書的作者竟然將這段代碼放在書的第二頁,我也是醉了,我覺得是挺難的,但不管怎樣,硬着頭皮上吧!
撲克牌排序規則:
用點數來判斷撲克牌的大小,2最小,A最大;同時還要加上對花色的判斷:
黑桃最大,紅桃次之,方塊再次,梅花最小。那么梅花2的大小是0,黑桃A是51.
分析一下這個函數:sorted(deck,key=spades_high),我在這里卡了很長時間,所以就有了上面的那塊磚,先說一下這個函數是怎么運行的吧:
通過sorted將deck這一摞牌和排序函數spades_high()聯系起來,每張牌都有數字,先獲取牌面的數字在FrenchDeck.ranks中的索引,即:2的索引0,
3的索引1,4的索引2,類推3,4,5,6,7,8,9,10,11,A的索引12,這張牌多大取決於它的花色,即索引 乘 4 加 花色值,
二、spades_high(card),這里的card就是傳進來的每一張牌,rank_values = FrenchDeck.ranks.index(card.rank),
獲取這張紙牌(即紙牌的數字)在FrenchDeck.ranks中的索引,['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
"最后返回這個牌的得分",rank_values * len(suit_values) + suit_values[card.suit],此時就講完了么?
靈光一閃,這個函數返回了所有得分有什么用?sorted()拿到這些得分,怎么把牌排好序?我覺得是這樣:
在得到了[所有得分]這個列表之后,進行排序,得到:[0,1,2,3,4,...51],
然后將原撲克列表中的元素,一一對應,是怎么對應的?函數在處理的時候應該記錄了每張卡的得分,所以能對應上。
如下(原來的撲克列表可不是這樣的,排好序的應該是重新開辟了一個內存空間):
[Card(rank='2', suit='clubs'),Card(rank='2', suit='diamonds'),Card(rank='2', suit='hearts'),...Card(rank='A', suit='spades')]
三、比如上面第一塊磚:
list1 = [3,5,-4,-1,0,-2,-6]
def get_abs(x):
return abs(x)
sorted(list1,key=get_abs)
函數先返回[3,5,4,1,0,2,6],然后排序[0,1,2,3,4,5,6],接着將list1中的每個元素,與排序后的列表對應,
0不變,1、2變成-1、-2,3不變,4變成-4,5不變,6變成-6,輸出[0,-1,-2,3,-4,5,-6]
四、看不懂的lambda,只是把這兩道題放在在這里提醒我,不要迷進去:
一道面試題: list1=[7, -8, 5, 4, 0, -2, -5] 要求1.正數在前負數在后 2.整數從小到大 3.負數從大到小 解題思路:先按照正負排先后,再按照大小排先后 list1=[7, -8, 5, 4, 0, -2, -5] print(sorted(list1,key=lambda x:(x<0,abs(x)))) [7, 5, 4, 0, -8, -2, -5] [0, 4, 5, 7, -2, -5, -8] 一個經典的復雜例子 這是一個字符串排序,排序規則:小寫<大寫<奇數<偶數 s = ‘asdf234GDSdsf23’ #排序:小寫-大寫-奇數-偶數 print(“”.join(sorted(s, key=lambda x: (x.isdigit(),x.isdigit() and int(x) % 2 == 0,x.isupper(),x)))) 原理:先比較元組的第一個值,FALSE
也不說什么臟話了,反正沒什么成就感,這些東西耗費我整整一天時間啊,就這本書作者隨手扔出來的一些小玩意,搞得我很不堪,
這就是傳說當中的以我之短擊他之長吧,法克!但還是會有不服,別人能會,我為什么嫌難,人總是活在矛盾中。總之,以后盡量不搞這些東西了。
