python高级特性的一般认识

zhglinux 2020-01-05

列表生成

[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对象,但listdictstr虽然是Iterable,却不是Iterator。可以用iter()函数让他们变成迭代器对象。

你可能会问,为什么listdictstr等数据类型不是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>

创建Lg的区别仅在于最外层的[]()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是惰性计算,按理来说可以计算到无穷大的数。

相关推荐