流畅的python--python的数据模型
如何使用特殊方法
import collections Card = collections.namedtuple('Card', ['rank', 'suit']) ''' class Card{ public string rank{get;set;} public string suit{get;set;} } ''' class FrenchDeck: ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() ''' _cards = List<Card>(): Card.rank = ranks[0]; Card.suit = suits[0]; ''' def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]
#python解释器在碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,特殊方法表示为:以两个下划线开头,以两个下划线结尾,比如以下__len__()方法和__getitem__()方法
#特殊方法名作用:能让你自己的对象实现和支持以下的语言框架,并与之交互,迭代、集合类、属性访问、运算符重载、函数和方法的调用、对象的创建和销毁、字符串表示形式和格式化、管理上下文(即with块)
#如何使用特殊方法:特殊方法的存在是为了被python解释器调用的,自己并不需要调用它们,也就是没有my_object.__len__()这种写法,而应该使用len(my_object) def __len__(self): return len(self._cards)
#比如obj[key]的背后就是__getitem__方法,为了能求得FrenchDeck[key]的值,解释器实际上会调用FrenchDeck.__getitem__(key) def __getitem__(self, position): return self._cards[position] beer_card = Card(rank='7', suit='diamonds') print(beer_card) # >> Card(rank='7', suit='diamonds')
deck = FrenchDeck() l = len(deck) #len方法是FrenchDeck类的特殊方法,实际调用的是deck.__len__(deck) print(l) # >>52
print(deck[0]) #实际调用的是 deck.__getitem__(0)方法
# >> Card(rank='2', suit='spades')
print(deck[-1]) #deck.getitem(12)
# >> Card(rank='A', suit='hearts') from random import choice tempCard= choice(deck) #随机抽取一张牌print(deck[:3]) print(deck[12::13]) #从12开始,每隔13张牌取一张 deck[12] deck[12+13] ...... for card in deck: # 正向循环 print(card)
'''
>>输出
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
Card(rank='5', suit='spades')
Card(rank='6', suit='spades')
......
'''
for card in reversed(deck): #反向循环
print(card)
'''
>>输出
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
Card(rank='J', suit='hearts')
Card(rank='10', suit='hearts')
......
'''
print(Card('Q', 'hearts') in deck) #判断Card('Q', 'hearts')在不在deck里
# >> true
print(Card('B', 'hearts') in deck) #判断Card('B', 'hearts')在不在deck里 # >> false suit_values = dict(spades=3, hearts=2, diamond=1, clubs=0) def spades_high(card): rank_value = FrenchDeck.ranks.index(card.rank) #找到牌面数字的下标
#对于deck类,print(card.rank, rank_value)
#>> 输出
'''
2 0
3 1
4 2
......
''' return rank_value * len(suit_values) + suit_values[card.suits] #得到每个元素的排序值
# 对于牌面值为2来说,2的下标为0,2有四种花色,rank_value * len(suit_values)得到了牌面值2的排序分数,suit_values[card.suits]代表每一种花色的排序数值分数,将两者相加,得到了牌面值2的整体排序分数 for card in sorted(deck, key=spades_high): print(card)
'''
>>输出
Card(rank='2', suit='clubs')
Card(rank='2', suit='diamonds')
Card(rank='2', suit='hearts')
Card(rank='2', suit='spades')
Card(rank='3', suit='clubs')
Card(rank='3', suit='diamonds')
Card(rank='3', suit='hearts')
......
'''
for card in sorted(deck, key=spades_high, reverse=True): #reverse参数表示正序倒序 print(card)
'''
>>输出
Card(rank='A', suit='spades')
Card(rank='A', suit='hearts')
Card(rank='A', suit='diamonds')
Card(rank='A', suit='clubs')
Card(rank='K', suit='spades')
Card(rank='K', suit='hearts')
Card(rank='K', suit='diamonds')
......
'''
字符串表达形式
from math import hypot class Vector: def __init__(self, x=0, y=0): self.x = x self.y = y #内置函数,得到类对象的字符串表示形式
#python有一个内置的函数是repr,它能把一个对象用字符串的形式表达出来以便辨认
#%和str.format这两种格式化字符串的方法目前都在使用,但是str.format可能会越来越适用
#__repr__和__str__的区别在于,后者是在str()函数被使用,或者是在print函数打印才被调用的,并且返回的字符串对终端用户更友好。如果只想实现这两种中的一种,那么__repr__会是更好的选择,因为如果一个对象没有 __str__ 函数,
#而 Python 又需要调用它的时候, 解释器会用 __repr__ 作为替代
def __repr__(self): return 'Vector(%r, %r)' %(self.x, self.y) def __abs__(self): return hypot(self.x, self.y) def __bool__(self): #布尔类型 return bool(abs(self)) def __add__(self, other): # + x = self.x + other.x y = self.y + other.y return Vector(x,y) def __mul__(self,scalar): # * return Vector(self.x * scalar, self.y * scalar) v1 = Vector(2, 4) print(v1) # >> Vector(2, 4) print(bool(v1)) # >> True print(abs(v1)) # >> 4.47213595499958 v2 = Vector(5,7) print(v1 + v2) # >> Vector(7, 11) print(v1 * 5) # >> Vector(10, 20)