第一章 Python数据模型

Magic 和 Dunder

指: Python中一双下划线包围的特殊方法,比如__len__,__iter__等,这类特殊方法又称作Dunder method,Magic method(魔法方法)是Python中特殊方法的昵称

特点

特殊方法的存在是为了被Python解释器调用,你自己无需调用它们,可以通过内置方法,比如len,iter,str等来间接使用特殊方法.

实现一摞Python风格的纸牌

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import collections

# 名字为Card的类,属性有rank,suit
Card = collections.namedtuple('Card',['rank','suit'])
class FrenchDesk:
# 牌的大小
ranks = [str(x) for x in range(2,11) ] + list('JQKA')
# 牌的花色
suits = 'spandes diamonds clubs hearts'.split(' ')

def __init__(self):
self.__cards = [Card(rank,suit) for suit in self.suits
for rank in self.ranks]

# 实现len()
def __len__(self):
return len(self.__cards)

# 实现[]取值
def __getitem__(self,position):
return self.__cards[position]

# 实现洗牌功能
def __setitem__(self,position,card):
self.__cards[position]=card

# 实现调试输出,返回一个字符串,代表FrenchDesk类信息
def __repr__(self):
return 'FrenchDesk类信息'

nametuple又叫做具名元组可以实现具有名字的元组或则具有名字的类,该类中只有属性,没有方法,本处就是利用具名元组实现Card


1
2
3
desk = FrenchDesk()
# 由于实现__getitem__,可以利用[]来索引元素
desk[5]

结果

1
Card(rank='7', suit='spandes')


1
2
3
# 输出desk类信息
# 利用__repr__
desk

结果

1
FrenchDesk类信息


1
2
3
from random import choice
# 随机输出desk中某个元素---随机抽取一张牌
choice(desk)

结果

1
Card(rank='4', suit='hearts')


1
2
3
# 由于实现__getitem__,FrenchDesk类具有列表的性质
# 所有可迭代的内置集合类型(list,str,tuple...)都具有切片的性质
desk[1::13]

结果

1
2
3
4
[Card(rank='3', suit='spandes'),
Card(rank='3', suit='diamonds'),
Card(rank='3', suit='clubs'),
Card(rank='3', suit='hearts')]

1
2
3
4
5
6
7
8
9
10
# 实现排序
suit_values=dict(spandes=3,hearts=2,diamonds=1,clubs=0)
# 对card进行排序
# 传入card,返回一个排序值(牌点数)
def spades_high(card):
rank_value=FrenchDesk.ranks.index(card.rank)
return rank_value*4+suit_values[card.suit]
# 对于每次迭代,会调用spades_high函数,参数为desk,然后进行排序
for card in sorted(desk,key=spades_high):
print(card)

结果

1
2
3
4
5
6
7
8
9
Card(rank='2', suit='clubs')
Card(rank='2', suit='diamonds')
Card(rank='2', suit='hearts')
Card(rank='2', suit='spandes')
...
Card(rank='A', suit='clubs')
Card(rank='A', suit='diamonds')
Card(rank='A', suit='hearts')
Card(rank='A', suit='spandes')


1
2
3
4
# 洗牌,打乱FreachDesk.__cards内部顺序
from random import shuffle
shuffle(desk)
desk[:5]

结果

1
2
3
4
5
[Card(rank='2', suit='clubs'),
Card(rank='10', suit='clubs'),
Card(rank='8', suit='clubs'),
Card(rank='A', suit='spandes'),
Card(rank='9', suit='hearts')]

1
2
shuffle(desk)
desk[:5]

结果

1
2
3
4
5
[Card(rank='6', suit='hearts'),
Card(rank='6', suit='spandes'),
Card(rank='J', suit='hearts'),
Card(rank='2', suit='diamonds'),
Card(rank='9', suit='clubs')]

实现向量运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from math import hypot
class Vector:
def __init__(self,x=0,y=0):
self.x = x
self.y = y

# 求模
def __abs__(self):
return hypot(self.x,self.y)

# 重载加法运算符
def __add__(self,other):
x = self.x + other.x
y = self.y + other.y
# 返回Vector
return Vector(x,y)

# 重载乘法
def __mul__(self,other):
x = self.x * other.x
y = self.y * other.y
return Vector(x,y)

def __bool__(self):
return bool(abs(self))

def __repr__(self):
return 'Vector(%r,%r)' % (self.x,self.y)

1
2
3
4
vector = Vector(3,5)
# 输出Vector类信息
# __repr__
vector
1
Vector(3,5)

1
2
# 加法
Vector(6,5) + Vector(6,-7)
1
Vector(12,-2)

1
2
# 乘法
Vector(6,5) * Vector(6,-7)
1
Vector(36,-35)

1
2
# 求模
abs(vector)
1
5.830951894845301

1
bool(vector)
1
True

总结

对于一个自建的类可以通过实现特殊方法来让类具有list,可迭代等特性.使自建类能表现的跟内置类一样,甚至功能更多.

本文标题:第一章 Python数据模型

文章作者:定。

发布时间:2017年5月24日 - 11时05分

本文字数:3,705字

原始链接:http://cocofe.cn/2017/05/24/第一章 Python数据模型/

许可协议: Attribution-NonCommercial 4.0

转载请保留以上信息。