用 python 差很少半年多了,从去年暑假开始接触,从开始的懵逼,到写了一些小爬虫总算入门以后,许多做业也是能用 python 就用 python,基本抛弃了 C++。可是仍是有些过于急躁了,可以写一些简短的代码,可是对于 python 的不少特性都不知道或者忘记了,这里回去廖大教程复习一下,顺便记录下我以为比较重要的地方。python
本文主要记录廖大教程中高级特性这一节的内容,并写下个人一些理解。在我看来,这些特性是很 pythonic 的,用在代码中颇有 bigger 啊~算法
切片和迭代就不说了,这里直接先看一下列表生成式吧,从名字就能大概猜出这是生成列表的一些方法,好比:如何生成[1*1, 2*2, ... ,10*10]
?能够用循环不断向列表尾部添加元素,若是使用 pythonic 的方法,也就是列表生成式,则是:函数
>>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
后面还能跟上 if 判断,例如:code
>>> [x * x for x in range(1, 11) if x%2==0] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
这样,原本须要使用循环写4,5行的代码,使用一行就解决了,直观明了。对象
还能使用两个 for 循环生成全排列:教程
>>> [m + n for m in 'ABC' for n in 'XYZ'] ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
这样如何添加 if 判断呢?能够在每一个 for 语句后添加,或者在最后添加:内存
>>> [m + n for m in 'ABC' if m < 'C' for n in 'XYZ' if n < 'Z'] ['AX', 'AY', 'BX', 'BY'] >>> [m + n for m in 'ABC' for n in 'XYZ' if n < 'Z' and m < 'C'] ['AX', 'AY', 'BX', 'BY']
也能够同时在一个 for 语句中迭代多个变量,好比dict的items()能够同时迭代key和value:get
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' } >>> [k + '=' + v for k, v in d.items()] ['y=B', 'x=A', 'z=C']
差很少就是这样了~generator
可是之前老是写 C++ ,这种思惟模式很难改过来,只能慢慢在使用中熟悉这种语法,习惯了就可以在下意识中写出来了。it
为何要使用生成器?廖大的教程中说得很详细,这里再简述一下:
由于列表的内容放在内存中,而受到内存限制,列表的容量有限。
若是咱们只访问极少的元素,那么存在极大的空间浪费。
而生成器能够一边迭代一边计算下一个值,理论上,该过程能够无限进行下去,而且不会占用大量内存。
这里只是简单介绍一下,更详细的请 Google 哈~
如何建立生成器?第一种方法相似于前面讲到的列表生成式,只须要将[]改成()便可:
>>> 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>
能够看到,方法上大体相同,[]获得的是一个已经获得全部值的列表,()获得的是一个生成器,它们都能使用 for 循环来迭代,可是生成器不能使用下标访问,而且只能被迭代一次,再次迭代则会有 StopIteration 的异常:
>>> for i in g: ... print(i) ... 0 1 4 9 16 25 36 49 64 81 >>> for i in g: ... print(i) ... >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
不过当咱们建立了一个generator后,基本上永远不会调用next(),而是经过for循环来迭代它,而且不须要关心StopIteration的错误。
若是推算的算法比较复杂,用相似列表生成式的for循环没法实现的时候,还能够用函数来实现,好比,著名的斐波那契数列:
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return 'done'
关于 yield 这个关键字,我在刚学 python 的时候也纠结了好久,直到看到生成器的时候才大体明白,你们搜索一下就能大体明白了,我以为这东西提及来麻烦,只说一两句又怕说错。廖大的教程中是这样说的:
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
可能有点难理解,不过明白了就很好说了。
固然,函数中还能够添加 return,在一个 generator function 中,若是没有 return,则默认执行至函数完毕,若是在执行过程当中 return,则直接抛出 StopIteration 终止迭代。
例如上面的例子,咱们在迭代时发现并无出现 'done' 这串字符,是由于 return 的值被看成 Exception Value 了,若是要显示出来,则能够这样:
>>> g = fib(6) >>> while True: ... try: ... x = next(g) ... print('g:', x) ... except StopIteration as e: ... print('Generator return value:', e.value) ... break ... g: 1 g: 1 g: 2 g: 3 g: 5 g: 8 Generator return value: done
可直接做用于 for 循环的对象被称为可迭代对象,能够用 isinstance() 函数判断是否为可迭代对象:
>>> from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance('abc', Iterable) True >>> isinstance((x for x in range(10)), Iterable) True >>> isinstance(100, Iterable) False
而能够被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。固然,仍然可使用isinstance()判断一个对象是不是Iterator对象:
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False
经过上面两个例子,能够这样理解:生成器和 list,tuple,str 等都是 Iterable 对象,生成器同时仍是 Iterator 对象,而 list 等不是。那么可否直接将 Iterable 对象转换成 Iterator 对象呢?
可使用iter()函数:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
其实,Iterator 对象表示的是一个数据流,咱们能够把这个数据流看作是一个有序序列,但却不能提早知道序列的长度,只能不断经过next()函数实现按需计算下一个数据,因此 Iterator 的计算是惰性的,只有在须要返回下一个数据时它才会计算。Iterator甚至能够表示一个无限大的数据流,但 list,tuple 什么的是不可能这样的。
过了个寒假没碰代码,至关于复习了一遍啊,其实这里说到的特性是很浅显的,理解起来不难,等所有差很少复习完还得再深刻一点,理解更多才行。
以上~