python高级特性的一般认识
列表生成
[x * x for x in range(1, 11)]
写列表生成式时,把要生成的元素x * x
放到前面,后面跟for
循环,或者跟其他的表达式。
例如,题目是要你把偶数全部筛选出来:
a=[x for x in range(1,11) if x%2==0] print(a) #[2, 4, 6, 8, 10]
python的哲学应该是代码写得越少越好,这样开发效率高。
迭代器
第一,像字符str,列表list,元组turple,字典dict等等都是可迭代对象iterable,内置有__iter__方法的对象,即obj.__iter__,如下
‘hello‘.__iter__ (1,2,3).__iter__ [1,2,3].__iter__ {‘a‘:1}.__iter__ {‘a‘,‘b‘}.__iter__ open(‘a.txt‘).__iter__
但是像这一类没有obj.__next__()方法。不能用next()方法去迭代。
第二,像generator生成器都是迭代器对象iterator,也就是说内置有__iter__方法以及__next__方法。
文件类型是迭代器对象 open(‘a.txt‘).__iter__() open(‘a.txt‘).__next__()
也就是说,生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。可以用iter()函数让他们变成迭代器对象。
你可能会问,为什么list
、dict
、str
等数据类型不是Iterator
?
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
生成器
1.第一种方法
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
>>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630>
创建L
和g
的区别仅在于最外层的[]
和()
,L
是一个list,而g
是一个generator。
我们使用next()或者.__next__()方法可以获得genereaor的下一个返回值:
>>> g = (x * x for x in range(10)) >>> next(g) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) 9 >>> next(g) 16 >>> next(g) 25 >>> next(g) 36 >>> next(g) 49 >>> next(g) 64 >>> next(g) 81 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>>
next()方法可以卡点。运行一次到下一个位置,然后再卡点,没有更多的元素时,抛出StopIteration
的错误。但是一直用next()属实sb,数据集太大怎么循环,所以用for,因为generator也是可迭代对象。
a=(x for x in range(1,11) if x%2==0) for i in a: print(i) 2 4 6 8 10
2.第二种方法
def odd(): print(‘step 1‘) yield 1 print(‘step 2‘) yield(3) print(‘step 3‘) yield(5) a=odd() res=next(a) print(a) print(res) step 1 <generator object odd at 0x0000025945C37660> 1
下面实现用yield和for循环对函数进行循环,准确来讲是迭代器函数(我自己起的名字)
def odd(): print(‘step 1‘) yield 1 print(‘step 2‘) yield(3) print(‘step 3‘) yield(5) # res=next(a) # print(a) # print(res) for i in odd(): print(i)
step 1 1 step 2 3 step 3 5
牛逼了,用yield将函数转化成生成器,让他可迭代,我查验了一下,odd()具备了iter和next方法,yield让函数有了"卡点"的功能。
for循环
#基于for循环,我们可以完全不再依赖索引去取值了 dic={‘a‘:1,‘b‘:2,‘c‘:3} for k in dic: print(dic[k]) #for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
就此我们知道了for的真正原理。还有可next()必是迭代器和生成器,它们表示一个惰性计算的序列;可iter()不一定是生成器迭代器,可能是可迭代对象iterable。
所以python里面的for是惰性计算,按理来说可以计算到无穷大的数。