第七篇:三元表达式、推导式、生成器、迭代器
三元表达式
num = float(input('请输入一个数字:')) result = '偶数' if num%2 == 0 else '奇数' print(result) '''类似于''' if num%2 == 0: print('偶数') else: print('奇数')
推导式
推导式是python提供的另一种创建数据类型的方式,有列表推导式、集合推导式、字典推导式,没有元祖推导式。
列表推导式
x = [1,2,3,4,5] y = [6,7,8,9,10] transfrom = [1 if i%2==0 else 0 for i in x if i > 2] print(transfrom) '''类似于''' transfroms = [] for i in x: if i > 2: if i%2==0: transfroms.append(1) else: transfroms.append(0) print(transfroms) result = [i+e for i in x if i%2==0 for e in y if e%2 == 0] print(result) print(type(result)) '''类似于''' results = [] for i in x: for e in y: if i%2==0: if e%2==0: results.append(i + e) print(results) '''1,2,3,4组成无重复三位数''' a = [str(i) for i in range(1,5)] f = [b+c+d for b in a for c in a for d in a if b != c != d != b] print(f)
集合推导式
'''1,2,3,4组成无重复三位数''' a = [str(i) for i in range(1,5)] f = {b+c+d for b in a for c in a for d in a if b != c != d != b} #把[]改为{}即可。 print(len(f))
字典推导式
x = [1,2,3,4,5] y = [6,7,8,9,10] result = {i:e for i,e in zip(x,y)} #zip函数返回zip对象,被遍历时返回一个序列下标相同的元素组成的元祖 res = {i:e for i,e in enumerate(y)} #enumerate()函数返回enumerate对象,被遍历时返回一个元祖(下标,元素)。 print(result) print(type(result)) '''类似于''' results = {} for i,e in enumerate(y): results[i] = e print(results) print(zip(x,y).__next__())
生成器
在Python中,列表,字典等序列的所有数据都在内存里,如果有海量数据,而我们仅仅需要访问几个元素的时候,那绝大多数元素占用的空间都白白浪费了。那么,有没有既想要得到庞大的数据,又想让它占用空间少的方法呢?,那就用生成器!按照某种算法不断推算出后续的元素,需要访问某个元素的时候,只需推算出,而不是从庞大的数据序列里取出
。这样一边循环一边计算的机制,称为生成器:generator。若要访问generate对象的元素,需要调用它的__next__()函数,或把generate对象传入next()函数,一个__next__()函数只拿出一个,之后循环停止在当前位置,下一个再取值再从停止位置继续向前取值。若推算完所有元素,还调用__next__(),则会抛出StopIteration异常,next()函数也一样。
创建生成器
'''方式一(生成器表达式):只要把一个列表推导式式的[]改成(),就创建了一个generator对象。''' generate = (e for e in range(1,100,2)) print(type(generate)) #访问元素 print(generate.__next__()) print(generate.__next__()) print(next(generate)) #在同一个对象里,无论调用next()或__next__()函数,它们都是接力推算的。 print(generate.__next__()) print(next(generate)) print("*"*10,end='\n'*2) generate2 = (e for e in range(1,10,2)) #重新创建新对象 for e in generate2: #for循环会不断调用__next__函数推算出后续元素,并返回它,直到捕获StopIteration异常,然后自动结束for循环。 print(e) '''方式二:如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。 调用函数就是创建了一个生成器(generator)对象。yield相当于 return 返回一个值,并且记住这个返回的位置, 下次迭代时,代码从yield的下一条语句开始执行。''' def test(seq): index = 0 while index < len(seq): yield seq[index] #遇到yield时,返回一个值,执行停止,并记住该位置,下次调用__next__()时,代码从yield的下一条语句开始执行。。 print('*'*10) print('上一个元素的下标是{}'.format(index)) index += 1 str1 = 'abcdefgh' generate3 = test(str1) print(type(generate3)) print(generate3.__next__()) print(generate3.__next__()) #.send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果. def test1(): count = 1 while count < 9: it = yield count print('*'*10) count += 1 if it: print('你第{}次使用的是:send()函数传值,并赋值给了变量step,step = {}'.format(count,it)) else: print('你第{}次使用的是:__next__()函数,未给变量step传值,默认值为None,step = None'.format(count)) generate4 = test1() print('返回值为:{}'.format(generate4.send(None))) #不能使用send()函数向刚启动的生成器发送非空值,不然使用__next__(),否则报错。 print('返回值为:{}'.format(generate4.send(6))) print('返回值为:{}'.format(generate4.send(8))) print('返回值为:{}'.format(generate4.__next__())) print('返回值为:{}'.format(generate4.send(9))) print('返回值为:{}'.format(generate4.__next__()))
def permutations(iterable, r=None): # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC # permutations(range(3)) --> 012 021 102 120 201 210 pool = tuple(iterable) n = len(pool) r = n if r is None else r if r > n: return indices = list(range(n)) cycles = list(range(n, n-r, -1)) yield tuple(pool[i] for i in indices[:r]) while n: for i in reversed(range(r)): cycles[i] -= 1 if cycles[i] == 0: indices[i:] = indices[i+1:] + indices[i:i+1] cycles[i] = n - i else: j = cycles[i] indices[i], indices[-j] = indices[-j], indices[i] yield tuple(pool[i] for i in indices[:r]) break else: return
迭代器
Iterable(可迭代对象)
: 有迭代能力的对象,一个类,实现了__iter__()
,那么就认为它有迭代能力,通常此函数返回一个实现了__next__()
的对象(虽然这个要求不强制),如果自己实现了,你可以返回self
,当然这个返回值不是必须的。
Iterator(迭代器)
: 迭代器(当然也是Iterable
),同时实现了__iter__()
和__next__()
的对象,缺少任何一个都不算是Iterator,其中
__next__()
应该在迭代完成后,抛出一个StopIteration
异常。
可以使用 collections.abc 里面的 Iterator
和 Iterable
配合 isinstance
函数来判断一个对象是否是可迭代的,是否是迭代器对象。
我们在使用for
语句的时候,python内部其实是把for
后面的对象上使用了内建函数iter()
,返回一个迭代器对象(Iterator)
,它主要映射到了类里面的__iter__()
函数,此函数返回的是一个实现了__next__
的对象。for
语句会自动处理这个StopIteration
异常以便结束for
循环。
from collections.abc import * list1 = [1,2,3,4,5] str1 = 'abcdef' list2iterator = iter(list1) #接受可迭代对象,返回迭代器对象。 str2iterator = iter(str1) '''isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。type() 不会认为子类是一种父类类型,不考虑继承关系。 isinstance() 会认为子类是一种父类类型,考虑继承关系。''' print('list1是可迭代对象吗?:{} | list1是迭代器对象吗?:{}'.format(isinstance(list1,Iterable),isinstance(list1,Iterator))) print('str1是可迭代对象吗?:{} | str1是迭代器对象吗?:{}'.format(isinstance(str1,Iterable),isinstance(str1,Iterator))) print('list2iterator是可迭代对象吗?:{} | list2iterator是迭代器对象吗?:{}'.format(isinstance(list2iterator,Iterable),isinstance(list2iterator,Iterator))) print('str2iterator是可迭代对象吗?:{} | str2iterator是迭代器对象吗?:{}'.format(isinstance(str2iterator,Iterable),isinstance(str2iterator,Iterator))) class B(object): def __next__(self): raise StopIteration class A(object): def __iter__(self): return B() a = A() b = B() print(isinstance(a, Iterable)) print(isinstance(a, Iterator)) print(isinstance(b, Iterable)) print(isinstance(b, Iterator)) '''制作自己的迭代器''' class MyIterator(): def __init__(self,seq): self.index = 0 self.seq = seq def __iter__(self): return self def __next__(self): if isinstance(self.seq,dict): self.seq = list(self.seq.values()) res = self.seq[self.index] self.index += 1 return res else: if self.index < len(self.seq): element = self.seq[self.index] self.index += 1 return element else: raise StopIteration() #在不想继续有迭代的情况下抛出一个StopIteration的异常,由for语句会捕获这个异常,并且自动结束for。 test = 'abcdef' testIter = MyIterator(test) print(isinstance(testIter,Iterable)) print(isinstance(MyIterator,Iterable)) #__iter__()和__next__()是类的普通方法,不是类方法或静态方法,只能被实例化对象调用,所以不能通过类名判断它是否是迭代器。 print(isinstance(MyIterator(test),Iterator))