hashable/iterable与orderable
1 ################ 2 # hashable协议 # 3 ################ 4 5 # 一个对象能被称为hashable,它必须实现__hash__与_eq__方法: 6 >>>{[1,2,3]} # TypeError: unhashable type: 'list' 7 >>>{{'Justin':123456}} # TypeError: unhashable type: 'dict' 8 >>>{{1,2,3}} # TypeError: unhashable type: 'set' 9 10 # 虽然p1与p3代表的是相同的坐标,但是集合中两个都收纳了,这是因为p1和p3使用默认的__hash__()获取的hash值不同 11 class Point: 12 def __init__(self,x,y): 13 self.x=x 14 self.y=y 15 def __repr__(self): 16 return 'Point({},{})'.format(self.x,self.y) 17 p1=Point(1,1) 18 p2=Point(2,2) 19 p3=Point(1,1) 20 ps={p1,p2,p3} 21 print(ps) # 显示{Point(1,1), Point(2,2), Point(1,1)} 22 23 # 如果想让集合能提出代表相同坐标的Point对象,必须自行实现__eq__()与__hash__()方法 24 class Point: 25 def __init__(self,x,y): 26 self.x=x 27 self.y=y 28 def __eq__(self, other): 29 if hasattr(other,'x') and hasattr(other,'y'): 30 return self.x == other.x and self.y ==other.y 31 return False 32 def __hash__(self): 33 return 41 * (41+self.x)+self.y 34 def __str__(self): 35 return self.__repr__() 36 def __repr__(self): 37 return 'Point({},{})'.format(self.x,self.y) 38 p1=Point(1,1) 39 p2=Point(2,2) 40 p3=Point(1,1) 41 ps={p1,p2,p3} 42 print(ps) # 显示{Point(1,1), Point(2,2)} 43 44 ################ 45 # iterable协议 # 46 ################ 47 48 # 具有__iter__()方法的对象,就是一个iterable(可迭代的)对象 49 # 生成器也是一种迭代器,对于大部分的迭代需求,使用yield语句创建生成器会比较简单和直接 50 def cycle(elems): 51 while True: 52 for elem in elems: 53 yield elem 54 abcd_gen=cycle(('abcd')) 55 print(next(abcd_gen)) 56 print(next(abcd_gen)) 57 print(next(abcd_gen)) 58 print(next(abcd_gen)) 59 print(next(abcd_gen)) 60 61 # 实现__iter__() 62 class Repeat: 63 def __init__(self,elem,n): 64 self.elem=elem 65 self.n=n 66 def __iter__(self): 67 elem=self.elem 68 n=self.n 69 class _Iter: 70 def __init__(self): 71 self.count=0 72 def __next__(self): 73 if self.count < n: 74 self.count += 1 75 return elem 76 else: 77 raise StopIteration 78 def __iter__(self): 79 return self 80 return _Iter() 81 for elem in Repeat('A',5): 82 print(elem,end=' ') 83 84 # 使用itertools模块 85 # 在Python标准链接库中提供了itertools模块,当中有许多函数可以谢谢胡创建迭代器和生成器 86 import itertools 87 print(list(itertools.repeat('A',10))) #['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'] 88 print(list(itertools.accumulate([1,2,3,4,5]))) # [1, 3, 6, 10, 15] 89 print(list(itertools.accumulate([1,2,3,4,5],int.__mul__))) # [1, 2, 6, 24, 120] 90 print((list(itertools.chain('ABC',[1,2,3])))) # ['A', 'B', 'C', 1, 2, 3] 91 print(list(itertools.chain.from_iterable(['ABC',[1,2,3]]))) # ['A', 'B', 'C', 1, 2, 3] 92 print(list(itertools.chain.from_iterable([[9,8,6],[1,2,3]]))) #[ 9, 8, 6, 1, 2, 3] 93 print(list(itertools.dropwhile(lambda x:x < 5,[1,4,6,4,1]))) # [6, 4, 1] 94 print(list(itertools.takewhile(lambda x:x < 5,[1,4,6,4,1]))) # [1, 4] 95 print(list(itertools.filterfalse(lambda x:x % 2,[1,2,3,4]))) # [2, 4] 96 97 # 有时候可能需要按某个键进行分类,可以使用itertools的groupby函数: 98 name=['Justin','Monica','Irene','Pika','caterpillar'] 99 group_by_name=itertools.groupby(name,lambda name:len(name)) 100 for length,group in group_by_name: 101 print(length,list(group)) 102 # 6 ['Justin', 'Monica'] 103 # 5 ['Irene'] 104 # 4 ['Pika'] 105 # 11 ['caterpillar'] 106 107 ################ 108 # orderable协议 # 109 ################ 110 111 # 如果希望使用自定义类型的sorted()或者使用列表的sort()时有默认的排序定义,那么必须实现__lt__()方法 112 class Customer: 113 def __init__(self,name,symbol,age): 114 self.name=name 115 self.symbol=symbol 116 self.age=age 117 def __lt__(self, other): 118 return self.name < other.name 119 def __str__(self): 120 return "Customer('{name}','{symbol}'".format(**vars(self)) 121 def __repr__(self): 122 return self.__str__() 123 customers=[ 124 Customer('Justin','A',40), 125 Customer('Irene','C',8), 126 Customer('Monica','B',37), 127 ] 128 print(sorted(customers)) # [Customer('Irene','C', Customer('Justin','A', Customer('Monica','B'] 129 130 # opertor模块的itemgetter和attrgetter,前者可以针对具有索引的结构,后者可以针对对象的属性 131 # 下面是使用itemgetter的示范: 132 from operator import itemgetter 133 custormers=[('Justin','A',40),('Irene','C',8),('Monica','B',37),] 134 print(sorted(custormers,key=itemgetter(0))) # [('Irene', 'C', 8), ('Justin', 'A', 40), ('Monica', 'B', 37)] 135 print(sorted(custormers,key=itemgetter(1))) # [('Justin', 'A', 40), ('Monica', 'B', 37), ('Irene', 'C', 8)] 136 print(sorted(custormers,key=itemgetter(2))) # [('Irene', 'C', 8), ('Monica', 'B', 37), ('Justin', 'A', 40)] 137 138 # 下面是使用attrgetter的示范: 139 from operator import attrgetter 140 class Customer: 141 def __init__(self,name,symbol,age): 142 self.name=name 143 self.symbol=symbol 144 self.age=age 145 def __repr__(self): 146 return "Customer('{name}','{symbol}',{age})".format(**vars(self)) 147 customers=[ 148 Customer('Justin','A',40), 149 Customer('Irene','C',8), 150 Customer('Monica','B',37), 151 ] 152 print(sorted(customers,key=attrgetter('name'))) 153 # [Customer('Irene','C',8), Customer('Justin','A',40), Customer('Monica','B',37)] 154 print(sorted(customers,key=attrgetter('symbol'))) 155 # [Customer('Justin','A',40), Customer('Monica','B',37), Customer('Irene','C',8)] 156 print(sorted(customers,key=attrgetter('age'))) 157 # [Customer('Irene','C',8), Customer('Monica','B',37), Customer('Justin','A',40)]