__getitem__()方法,我们可以创建一些有容器特征的类,并且可以用内建的操作函数对这些自定义的容器类进行操作, 例如[]、len()、for等。因为这些方法的实现本质上就是在调用类中的这些特殊方法import collections
from random import choice
# collections.nametuple()适合用于构建有属性但是没有方法的对象,例如数据库中的一条记录;
Card = collections.namedtuple("Card",['rank','suit'])
class FrenchDeck(object):
'''
一个扑克牌类,包含扑克牌以及对扑克牌的操作;
'''
ranks = [str(n) for n in range(2,11) ]+ list("JQKA")
suits = "spades diamonds clubs hearts".split(" ")
def __init__(self):
self._cards = [Card(rank,suit) for rank in self.ranks
for suit in self.suits]
def __len__(self):
return len(self._cards)
def __getitem__(self,pos:int):
return self._cards[pos]
#由于实现了__getitem__()方法,
bd = FrenchDeck()
print(f"一共有{len(bd)}张牌")
i = 13
print(f'第{i}张卡是{bd[i]}')
# 抽取扑克牌的最后一章
print(f"最后一张牌是{bd[-1]}")
#随机选择元素
print(f"随机选择一个元素的结果{choice(bd)}")
# 得益于__getitem__()方法将操作委托给列表[]运算符,于是适用于列表的操作都能够在FrenchDeck类上实现,例如切片
print(f"对FrenchDeck类的实例进行切片操作:12:24-> {bd[12:24]}\n长度{len(bd[12:24])}")__getitem__()方法后,也可以用sort()函数进行排序,并且通过某个操作对顺序进行打乱,实现洗牌的操作;# 实现排序
# 由于在扑克牌中,按点数A最大,以及黑桃最大
suit_value = dict(
diamonds = 0, #方块
clubs = 1, # 梅花
hearts = 3, # 红心
spades = 4 # 黑桃
)
def ref_card_value(card):
rand_val = FrenchDeck.ranks.index(card.rank)
return rand_val*len(suit_value) + suit_value[card.suit]
sorted_deck = sorted(deck, key=ref_card_value, reverse=True)
for c in sorted_deck:
print(c)python解析器调用,而不是你自己。也就是说,没有my_object.__len__()这种写法,正确写法是len(my_object)。def __init__(self)方法:可以通过调用这个特殊方法,对对象进行初始化。__add__(),__sub__(),__mul__(),__abs__(),__bool__()等。__repr__()和__str__()都可以提供打印对象字符串格式的方式,其中__str__()是调用str()方法时调用的。通常情况下,__repr__()会表现得足够好以至于我们无需重复实现两个方法。在Python中如果二选一的话一定要选择__repr__()。'''
实现一个Vector类
'''
'''
1.3 通过特殊方法实现特定的数值类型
例如:向量、标量或者满足某类操作的数据和数据操作;
'''
import math
class Vector(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
'''
向量加法
'''
if isinstance(other, Vector):
return Vector(self.x + other.x, self.y + other.y)
else:
raise TypeError("Unsupported operand type for +: 'Vector' and '{}'".format(type(other).__name__))
def __repr__(self):
'''
返回向量的字符串表示
'''
return f"Vector(x={self.x},y={self.y})"
def __abs__(self):
'''
返回向量的长度
'''
return math.sqrt(self.x**2 + self.y**2)
v = Vector(1, 2)
u = Vector(3, 4)
w = v + u
print(w)
print(abs(w))

Iterable要支持for、拆包和其他迭代方式Sized要支持内置函数(bulit-in)len。Container要支持in运算。拆包:简单来说就是将可迭代对象(比如列表、元组、字典、字符串等)中的元素 “拆解” 出来,分别赋值给多个变量,或者传递给函数的多个参数。
*变量名接收剩余的所有元素(会打包成列表),这也叫 “扩展拆包”key,如果要拆包value需用values(),拆包key-value对需用items()# 1. 元组拆包(最常用)
person = ("张三", 25, "北京")
name, age, city = person # 拆包:将元组的3个元素分别赋值给3个变量
print(name) # 输出:张三
print(age) # 输出:25
print(city) # 输出:北京
# 2. 列表拆包
nums = [10, 20, 30]
a, b, c = nums
print(a + b + c) # 输出:60
# 3. 字符串拆包(字符串是字符的可迭代对象)
s = "abc"
x, y, z = s
print(x) # 输出:al = ['name','age','gener','score']
name,age,*rest = l
print(name)
print(age)
print(rest)d = {'name':'张三','age':18,'gener':'男','score':100}
# 1. 默认拆包的是key
name,age,gender,score = d
print(name)
print(age)
print(gender)
print(score)
# 2. 拆包value,需要专门调用values()方法
name,age,gender,score = d.values()
print(name)
print(age)
print(gender)
print(score)
# 3. key,value对
name,age,gender,score = d.items()
print(name)
print(age)
print(gender)
print(score)
#OUTPUT
#('name', '张三')
#('age', 18)
#('gener', '男')
#('score', 100)Collection有3个十分重要的专用接口:Sequence规范list和str等内置类型接口;Mapping被dict,collections.defaultdict等实现;Set是set和frozenset两个内置类型的接口
