python生成器/内置函数
1.摘要
- 内置函数
- 生成器/迭代器
- 常用模块
2.内置函数
1 abs() --取绝对值 2 3 all() --任意一个元素为0,空,或者false,则返回False,否则返回为True,特别的[],(),{}返回为True 4 5 any() --任意一个元素不为0,空,或者false,则返回True,否则返回为False 6 7 ascii() --转换为ascii对应的字符 8 9 bin() --二进制 10 hex() --16进制 11 oct() --8进制 12 13 bool() 14 15 bytearray() --bytes和字符串不能被修改,byetarray 直接在原内存地址修改 16 memoryview() --允许直接修改原内存,参数为bytes格式 17 18 19 bytes() 20 21 callable() --是否为可调用的,如函数 22 23 chr() --数字转换成对应ascii字符 24 25 ord() --与chr相反 26 27 eval --字符串形式的表达式解析并执行 28 29 exec() ----字符串形式的代码解析并执行 30 31 compile() --把一个代码文件加载进来,按exec或eval大方式解析并执行 32 33 dir() --查看对象的方法 34 两个__--私有方法 35 36 divmod() 返回余数和商 37 38 filter() --返回函数结果为True的列表值 39 a = range(0,10) 40 b = filter(lambda x:x>5,a) --返回结果为true的a中的值 41 42 for i in b: 43 print(i) 44 45 format() 46 frozenset() --让集合可修改 47 globals() --当前的程序所有的全局变量以字典的形式展示 48 locals() --当前的函数所有的全局变量以字典的形式展示 49 50 hash() --只能保证在当前程序是唯一的,退出后重新执行,不同 51 52 53 isinstance() --判断一个对象是不是实例 54 55 56 map() -- 57 from functools import reduce 58 a = reduce(lambda x,y:x+y ,range(10)) 59 print(a) --45 60 61 62 63 import time 64 for i in range(20): 65 time.sleep(0.5) 66 print("#",end='',flush=True) 67 68 print(...) 69 print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) 70 Prints the values to a stream, or to sys.stdout by default. 71 Optional keyword arguments: 72 file: a file-like object (stream); defaults to the current sys.stdout. 73 sep: string inserted between values, default a space. 74 end: string appended after the last value, default a newline. 75 flush: whether to forcibly flush the stream. 76 77 78 repr() -- 79 80 81 reversed() --反转 82 round(5.23353,2) --保留2位小数 83 84 a = list() 85 compile 86 f = open("函数递归.py") 87 data =compile(f.read(),'','exec') 88 exec(data) 89 90 91 print 92 msg = "又回到最初的起点" 93 f = open("tofile","w") 94 print(msg,"记忆中你青涩的脸",sep="|",end="",file=f) 95 #slice 96 a = range(20) 97 pattern = slice(3,8,2) 98 for i in a[pattern]: #等于a[3:8:2] 99 print(i) 100 101 102 103 104 memoryview 105 usage: 106 >>> memoryview(b'abcd') 107 <memory at 0x104069648> 108 在进行切片并赋值数据时,不需要重新copy原列表数据,可以直接映射原数据内存, 109 110 111 import time 112 for n in (100000, 200000, 300000, 400000): 113 data = b'x'*n 114 start = time.time() 115 b = data 116 while b: 117 b = b[1:] 118 print('bytes', n, time.time()-start) 119 120 for n in (100000, 200000, 300000, 400000): 121 data = b'x'*n 122 start = time.time() 123 b = memoryview(data) 124 while b: 125 b = b[1:] 126 print('memoryview', n, time.time()-start) 127 128 几个内置方法用法提醒 129 130 zip() 131 按照位置一一合并 132 133 134 __import__() --用户输入的为字符串,导入用户输入的模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
abs() --取绝对值 all() --任意一个元素为0,空,或者false,则返回False,否则返回为True,特别的[],(),{}返回为True any() --任意一个元素不为0,空,或者false,则返回True,否则返回为False ascii() --转换为ascii对应的字符 bin() --二进制 hex() --16进制 oct() --8进制 bool() bytearray() --bytes和字符串不能被修改,byetarray 直接在原内存地址修改 memoryview() --允许直接修改原内存,参数为bytes格式 bytes() callable() --是否为可调用的,如函数 chr() --数字转换成对应ascii字符 ord() --与chr相反 eval --字符串形式的表达式解析并执行 exec() ----字符串形式的代码解析并执行 compile() --把一个代码文件加载进来,按exec或eval大方式解析并执行 dir() --查看对象的方法 两个__--私有方法 divmod() 返回余数和商 filter() --返回函数结果为True的列表值 a = range(0,10) b = filter(lambda x:x>5,a) --返回结果为true的a中的值 for i in b: print(i) format() frozenset() --让集合可修改 globals() --当前的程序所有的全局变量以字典的形式展示 locals() --当前的函数所有的全局变量以字典的形式展示 hash() --只能保证在当前程序是唯一的,退出后重新执行,不同 isinstance() --判断一个对象是不是实例 map() -- from functools import reduce a = reduce(lambda x,y:x+y ,range(10)) print(a) --45 import time for i in range(20): time.sleep(0.5) print("#",end='',flush=True) print(...) print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream. repr() -- reversed() --反转 round(5.23353,2) --保留2位小数 a = list() compile f = open("函数递归.py") data =compile(f.read(),'','exec') exec(data) print msg = "又回到最初的起点" f = open("tofile","w") print(msg,"记忆中你青涩的脸",sep="|",end="",file=f) #slice a = range(20) pattern = slice(3,8,2) for i in a[pattern]: #等于a[3:8:2] print(i) memoryview usage: >>> memoryview(b'abcd') <memory at 0x104069648> 在进行切片并赋值数据时,不需要重新copy原列表数据,可以直接映射原数据内存, import time for n in (100000, 200000, 300000, 400000): data = b'x'*n start = time.time() b = data while b: b = b[1:] print('bytes', n, time.time()-start) for n in (100000, 200000, 300000, 400000): data = b'x'*n start = time.time() b = memoryview(data) while b: b = b[1:] print('memoryview', n, time.time()-start) 几个内置方法用法提醒 zip() 按照位置一一合并 __import__() --用户输入的为字符串,导入用户输入的模块
3.生成器/迭代器
3.1生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
1 a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 2 3 for k,v in enumerate(a): 4 a[k] = v +1 5 6 print(a) 7 8 列表生成式 9 a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 10 a = [i+1 for i in a] 11 print(a) 12 13 a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 14 a = [i*i if i > 5 else i for i in a] 15 print(a) 16 17 18 --生成器generator 19 a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 20 a = (i*i if i > 5 else i for i in a) 21 print(next(a)) 22 print(a.__next__()) 23 24 fib() 25 26 生成器 yeild保存了函数的中断状态 27 28 def fib(max): 29 n,a,b = 0,0,1 30 while n < max: 31 yield b 32 a,b = b ,a+b 33 n += 1 34 35 return "done" 36 37 f = fib(15) 38 print(f.__next__()) 39 print(f.__next__()) 40 print("调用其他函数") 41 print(f.__next__()) 42 print(f.__next__()) 43 print(f.__next__()) 44 print(f.__next__())
1 >>> L = [x * x for x in range(10)] 2 >>> L 3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 4 >>> g = (x * x for x in range(10)) 5 >>> g 6 <generator object <genexpr> at 0x1022ef630>
创建L
和g
的区别仅在于最外层的[]
和()
,L
是一个list,而g
是一个generator。
我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?
如果要一个一个打印出来,可以通过next()
函数获得generator的下一个返回值:
1 >>> next(g) 2 0 3 >>> next(g) 4 1
我们讲过,generator保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
当然,上面这种不断调用next(g)
实在是太变态了,正确的方法是使用for
循环,因为generator也是可迭代对象:
1 >>> g = (x * x for x in range(10)) 2 >>> for n in g: 3 ... print(n) 4 ... 5 0 6 1 7 4 8 9 9 16 10 25 11 36 12 49 13 64 14 81
所以,我们创建了一个generator后,基本上永远不会调用next()
,而是通过for
循环来迭代它,并且不需要关心StopIteration
的错误。
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
1 def fib(max): 2 n, a, b = 0, 0, 1 3 while n < max: 4 print(b) 5 a, b = b, a + b 6 n = n + 1 7 return 'done'
注意,赋值语句:
1 a, b = b, a + b 2 3 相当于: 4 5 t = (b, a + b) # t是一个tuple 6 a = t[0] 7 b = t[1]
但不必显式写出临时变量t就可以赋值。
上面的函数可以输出斐波那契数列的前N个数:
1 >>> fib(10) 2 1 3 1 4 2 5 3 6 5 7 8 8 13 9 21 10 34 11 55 12 done
仔细观察,可以看出,fib
函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib
函数变成generator,只需要把print(b)
改为yield b
就可以了:
1 def fib(max): 2 n,a,b = 0,0,1 3 4 while n < max: 5 #print(b) 6 yield b 7 a,b = b,a+b 8 9 n += 1 10 11 return 'done'
这就是定义generator的另一种方法。如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator:
1 >>> f = fib(6) 2 >>> f 3 <generator object fib at 0x104feaaa0>
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
1 data = fib(10) 2 print(data) 3 4 print(data.__next__()) 5 print(data.__next__()) 6 print("干点别的事") 7 print(data.__next__()) 8 print(data.__next__()) 9 print(data.__next__()) 10 print(data.__next__()) 11 print(data.__next__()) 12 13 #输出 14 <generator object fib at 0x101be02b0> 15 1 16 干点别的事 17 3 18 8
在上面fib
的例子,我们在循环过程中不断调用yield
,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。
同样的,把函数改成generator后,我们基本上从来不会用next()
来获取下一个返回值,而是直接使用for
循环来迭代:
1 >>> for n in fib(6): 2 ... print(n) 3 ... 4 1 5 3 6 8
但是用for
循环调用generator时,发现拿不到generator的return
语句的返回值。如果想要拿到返回值,必须捕获StopIteration
错误,返回值包含在StopIteration
的value
中:
1 >>> g = fib(6) 2 >>> while True: 3 ... try: 4 ... x = next(g) 5 ... print('g:', x) 6 ... except StopIteration as e: 7 ... print('Generator return value:', e.value) 8 ... break 9 ... 10 g: 1 11 g: 1 12 g: 2 13 g: 3 14 g: 5 15 g: 8 16 Generator return value: done
还可通过yield实现在单线程的情况下实现并发运算的效果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#_*_coding:utf-8_*_ __author__ = 'Alex Li' import time def consumer(name): print("%s 准备吃包子啦!" %name) while True: baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') c.__next__() c2.__next__() print("老子开始准备做包子啦!") for i in range(10): time.sleep(1) print("做了2个包子!") c.send(i) c2.send(i) producer("alex") 通过生成器实现协程并行运算
3.2迭代器
我们已经知道,可以直接作用于for
循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。可以使用isinstance()
判断一个对象是否是Iterable
对象:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
>>> 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
而生成器不但可以作用于for
循环,还可以被next()
函数不断调用并返回下一个值,直到最后抛出StopIteration
错误表示无法继续返回下一个值了。
*可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
可以使用isinstance()
判断一个对象是否是Iterator
对象:
1 >>> from collections import Iterator 2 >>> isinstance((x for x in range(10)), Iterator) 3 True 4 >>> isinstance([], Iterator) 5 False 6 >>> isinstance({}, Iterator) 7 False 8 >>> isinstance('abc', Iterator) 9 False
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
1 >>> isinstance(iter([]), Iterator) 2 True 3 >>> isinstance(iter('abc'), Iterator) 4 True
你可能会问,为什么list
、dict
、str
等数据类型不是Iterator
?
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
Python的for
循环本质上就是通过不断调用next()
函数实现的,例如:
1 for x in [1, 2, 3, 4, 5]: 2 pass 3 4 实际上完全等价于: 5 6 # 首先获得Iterator对象: 7 it = iter([1, 2, 3, 4, 5]) 8 # 循环: 9 while True: 10 try: 11 # 获得下一个值: 12 x = next(it) 13 except StopIteration: 14 # 遇到StopIteration就退出循环 15 break
4.常用模块
4.1time &datetime模块
1 #_*_coding:utf-8_*_ 2 __author__ = 'Alex Li' 3 4 import time 5 6 7 # print(time.clock()) #返回处理器时间,3.3开始已废弃 , 改成了time.process_time()测量处理器运算时间,不包括sleep时间,不稳定,mac上测不出来 8 # print(time.altzone) #返回与utc时间的时间差,以秒计算\ 9 # print(time.asctime()) #返回时间格式"Fri Aug 19 11:14:16 2016", 10 # print(time.localtime()) #返回本地时间 的struct time对象格式 11 # print(time.gmtime(time.time()-800000)) #返回utc时间的struc时间对象格式 12 13 # print(time.asctime(time.localtime())) #返回时间格式"Fri Aug 19 11:14:16 2016", 14 #print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上 15 16 17 18 # 日期字符串 转成 时间戳 19 # string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #将 日期字符串 转成 struct时间对象格式 20 # print(string_2_struct) 21 # # 22 # struct_2_stamp = time.mktime(string_2_struct) #将struct时间对象转成时间戳 23 # print(struct_2_stamp) 24 25 26 27 #将时间戳转为字符串格式 28 # print(time.gmtime(time.time()-86640)) #将utc时间戳转换成struct_time格式 29 # print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将utc struct_time格式转成指定的字符串格式 30 31 32 33 34 35 #时间加减 36 import datetime 37 38 # print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925 39 #print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19 40 # print(datetime.datetime.now() ) 41 # print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天 42 # print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天 43 # print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时 44 # print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分 45 46 47 # 48 # c_time = datetime.datetime.now() 49 # print(c_time.replace(minute=3,hour=2)) #时间替换
4.2random模块
1 import random 2 print random.random() 3 print random.randint(1,2) 4 print random.randrange(1,10) 5 6 7 生成随机验证码 8 9 import random 10 checkcode = '' 11 for i in range(4): 12 current = random.randrange(0,4) 13 if current != i: 14 temp = chr(random.randint(65,90)) 15 else: 16 temp = random.randint(0,9) 17 checkcode += str(temp) 18 print checkcode
4.3os模块
1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 2 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd 3 os.curdir 返回当前目录: ('.') 4 os.pardir 获取当前目录的父目录字符串名:('..') 5 os.makedirs('dirname1/dirname2') 可生成多层递归目录 6 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 7 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname 8 os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname 9 os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 10 os.remove() 删除一个文件 11 os.rename("oldname","newname") 重命名文件/目录 12 os.stat('path/filename') 获取文件/目录信息 13 os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" 14 os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" 15 os.pathsep 输出用于分割文件路径的字符串 16 os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' 17 os.system("bash command") 运行shell命令,直接显示 18 os.environ 获取系统环境变量 19 os.path.abspath(path) 返回path规范化的绝对路径 20 os.path.split(path) 将path分割成目录和文件名二元组返回 21 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 22 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 23 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False 24 os.path.isabs(path) 如果path是绝对路径,返回True 25 os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False 26 os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False 27 os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 28 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 29 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
4.4sys模块
1 sys.argv 命令行参数List,第一个元素是程序本身路径 2 sys.exit(n) 退出程序,正常退出时exit(0) 3 sys.version 获取Python解释程序的版本信息 4 sys.maxint 最大的Int值 5 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 6 sys.platform 返回操作系统平台名称 7 sys.stdout.write('please:') 8 val = sys.stdin.readline()[:-1]
4.5json和pickle模块
用于序列化的两个模块
- json,用于字符串 和 python数据类型间进行转换
- pickle,用于python特有的类型 和 python的数据类型间进行转换
Json模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load
4.6 logging
1 import logging 2 3 #create logger 4 logger = logging.getLogger('TEST-LOG') 5 logger.setLevel(logging.DEBUG) 6 7 8 # create console handler and set level to debug 9 ch = logging.StreamHandler() 10 ch.setLevel(logging.DEBUG) 11 12 # create file handler and set level to warning 13 fh = logging.FileHandler("access.log") 14 fh.setLevel(logging.WARNING) 15 # create formatter 16 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 17 18 # add formatter to ch and fh 19 ch.setFormatter(formatter) 20 fh.setFormatter(formatter) 21 22 # add ch and fh to logger 23 logger.addHandler(ch) 24 logger.addHandler(fh) 25 26 # 'application' code 27 logger.debug('debug message') 28 logger.info('info message') 29 logger.warn('warn message') 30 logger.error('error message') 31 logger.critical('critical message')