一 装饰器

1.1 函数对象

一 函数是第一类对象,即函数可以当作数据传递

  1. #1 可以被引用
  2. #2 可以当作参数传递
  3. #3 返回值可以是函数
  4. #3 可以当作容器类型的元素

二 利用该特性,优雅的取代多分支的if

  1. def foo():
  2. print('foo')
  3.  
  4. def bar():
  5. print('bar')
  6.  
  7. dic={
  8. 'foo':foo,
  9. 'bar':bar,
  10. }
  11. while True:
  12. choice=input('>>: ').strip()
  13. if choice in dic:
  14. dic[choice]()

1.2 函数嵌套

一 函数的嵌套调用

  1. def max(x,y):
  2. return x if x > y else y
  3.  
  4. def max4(a,b,c,d):
  5. res1=max(a,b)
  6. res2=max(res1,c)
  7. res3=max(res2,d)
  8. return res3
  9. print(max4(1,2,3,4))

二 函数的嵌套定义

  1. def f1():
  2. def f2():
  3. def f3():
  4. print('from f3')
  5. f3()
  6. f2()
  7.  
  8. f1()
  9. f3() #报错,为何?请看下一小节

1.3 名称空间和作用域

一 什么是名称空间?

  1. #名称空间:存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)

二 名称空间的加载顺序

  1. python test.py
  2. #1、python解释器先启动,因而首先加载的是:内置名称空间
  3. #2、执行test.py文件,然后以文件为基础,加载全局名称空间
  4. #3、在执行文件的过程中如果调用函数,则临时产生局部名称空间

三 名字的查找顺序

  1. 局部名称空间--->全局名称空间--->内置名称空间
  2.  
  3. #需要注意的是:在全局无法查看局部的,在局部可以查看全局的,如下示例
  4.  
  5. # max=1
  6. def f1():
  7. # max=2
  8. def f2():
  9. # max=3
  10. print(max)
  11. f2()
  12. f1()
  13. print(max)

四 作用域

  1. #1、作用域即范围
  2. - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
  3.   - 局部范围(局部名称空间属于该范围):临时存活,局部有效
  4. #2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
  5. x=1
  6. def f1():
  7. def f2():
  8. print(x)
  9. return f2
  10. x=100
  11. def f3(func):
  12. x=2
  13. func()
  14. x=10000
  15. f3(f1())
  16.  
  17. #3、查看作用域:globals(),locals()
  18.  
  19. LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
  20. locals 是函数内的名字空间,包括局部变量和形参
  21. enclosing 外部嵌套函数的名字空间(闭包中常见)
  22. globals 全局变量,函数定义所在模块的名字空间
  23. builtins 内置模块的名字空间

五 global与nonlocal关键字

1.4 闭包函数

一 什么是闭包?

  1. #内部函数包含对外部作用域而非全局作用域的引用
  2.  
  3. #提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来喽,包起呦,包起来哇
  4.  
  5. def counter():
  6. n=0
  7. def incr():
  8. nonlocal n
  9. x=n
  10. n+=1
  11. return x
  12. return incr
  13.  
  14. c=counter()
  15. print(c())
  16. print(c())
  17. print(c())
  18. print(c.__closure__[0].cell_contents) #查看闭包的元素

二 闭包的意义与应用

  1. #闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
  2. #应用领域:延迟计算(原来我们是传参,现在我们是包起来)
  3. from urllib.request import urlopen
  4.  
  5. def index(url):
  6. def get():
  7. return urlopen(url).read()
  8. return get
  9.  
  10. baidu=index('http://www.baidu.com')
  11. print(baidu().decode('utf-8'))

1.5 装饰器

一 为何要用装饰器

  1. #开放封闭原则:对修改封闭,对扩展开放

二 什么是装饰器

  1. 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
  2. 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
  3. 装饰器的目标:在遵循12的前提下,为被装饰对象添加上新功能

三 装饰器的使用

  1. import time
  2. def timmer(func):
  3. def wrapper(*args,**kwargs):
  4. start_time=time.time()
  5. res=func(*args,**kwargs)
  6. stop_time=time.time()
  7. print('run time is %s' %(stop_time-start_time))
  8. return res
  9. return wrapper
  10.  
  11. @timmer
  12. def foo():
  13. time.sleep(3)
  14. print('from foo')
  15. foo()
  16.  
  17. 无参装饰器

无参装饰器

  1. def auth(driver='file'):
  2. def auth2(func):
  3. def wrapper(*args,**kwargs):
  4. name=input("user: ")
  5. pwd=input("pwd: ")
  6.  
  7. if driver == 'file':
  8. if name == 'egon' and pwd == '':
  9. print('login successful')
  10. res=func(*args,**kwargs)
  11. return res
  12. elif driver == 'ldap':
  13. print('ldap')
  14. return wrapper
  15. return auth2
  16.  
  17. @auth(driver='file')
  18. def foo(name):
  19. print(name)
  20.  
  21. foo('egon')
  22.  
  23. 有参装饰器

有参装饰器

四 装饰器语法

  1. 被装饰函数的正上方,单独一行
  2. @deco1
  3. @deco2
  4. @deco3
  5. def foo():
  6. pass
  7.  
  8. foo=deco1(deco2(deco3(foo)))

五 装饰器补充:wraps

  1. from functools import wraps
  2.  
  3. def deco(func):
  4. @wraps(func) #加在最内层函数正上方
  5. def wrapper(*args,**kwargs):
  6. return func(*args,**kwargs)
  7. return wrapper
  8.  
  9. @deco
  10. def index():
  11. '''哈哈哈哈'''
  12. print('from index')
  13.  
  14. print(index.__doc__)

六 练习

一:编写函数,(函数执行的时间是随机的)
二:编写装饰器,为函数加上统计时间的功能
三:编写装饰器,为函数加上认证的功能

四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式

五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录

六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果

七:为题目五编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中

扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中

八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作

九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
注意:时间格式的获取
import time
time.strftime('%Y-%m-%d %X')

  1. #题目一:
  2. import time,random
  3. ran = random.random()
  4. def foo():
  5. time.sleep(ran)
  6. print("Done")
  7. foo()
  8. #题目二:
  9. import time,random
  10. ran = random.random()
  11. def timer(func):
  12. def inner():
  13. start_time = time.time()
  14. func()
  15. stop_time = time.time()
  16. print("TIME>> %s" %(stop_time-start_time))
  17. return inner
  18. @timer
  19. def foo():
  20. time.sleep(ran)
  21. print("Done")
  22. foo()
  23. #题目三:
  24. import time,random
  25. ran = random.random()
  26. def auth(bar):
  27. def inner():
  28. info = {
  29. "lizhong":123,
  30. "hehe":234,
  31. }
  32. name = input("user>>").strip()
  33. if name in info:
  34. pwd = int(input("pwd>>").strip())
  35. if pwd == info[name]:
  36. print("Login success")
  37. bar()
  38. else:
  39. print("Login faild")
  40. else:
  41. print("No such user")
  42. return inner
  43. def timer(func):
  44. def inner():
  45. start_time = time.time()
  46. func()
  47. stop_time = time.time()
  48. print("TIME>> %s" %(stop_time-start_time))
  49. return inner
  50. @auth
  51. @timer
  52. def foo():
  53. time.sleep(ran)
  54. print("Done")
  55. while True:
  56. foo()
  57. #题目四:
  58. db='db.txt'
  59. login_status={'user':None,'status':False}
  60. def auth(auth_type='file'):
  61. def auth2(func):
  62. def wrapper(*args,**kwargs):
  63. if login_status['user'] and login_status['status']:
  64. return func(*args,**kwargs)
  65. if auth_type == 'file':
  66. with open(db,encoding='utf-8') as f:
  67. dic=eval(f.read())
  68. name=input('username: ').strip()
  69. password=input('password: ').strip()
  70. if name in dic and password == dic[name]:
  71. login_status['user']=name
  72. login_status['status']=True
  73. res=func(*args,**kwargs)
  74. return res
  75. else:
  76. print('username or password error')
  77. elif auth_type == 'sql':
  78. pass
  79. else:
  80. pass
  81. return wrapper
  82. return auth2
  83.  
  84. @auth()
  85. def index():
  86. print('index')
  87.  
  88. @auth(auth_type='file')
  89. def home(name):
  90. print('welcome %s to home' %name)
  91.  
  92. # index()
  93. # home('egon')
  94.  
  95. #题目五
  96. import time,random
  97. user={'user':None,'login_time':None,'timeout':0.000003,}
  98.  
  99. def timmer(func):
  100. def wrapper(*args,**kwargs):
  101. s1=time.time()
  102. res=func(*args,**kwargs)
  103. s2=time.time()
  104. print('%s' %(s2-s1))
  105. return res
  106. return wrapper
  107.  
  108. def auth(func):
  109. def wrapper(*args,**kwargs):
  110. if user['user']:
  111. timeout=time.time()-user['login_time']
  112. if timeout < user['timeout']:
  113. return func(*args,**kwargs)
  114. name=input('name>>: ').strip()
  115. password=input('password>>: ').strip()
  116. if name == 'egon' and password == '':
  117. user['user']=name
  118. user['login_time']=time.time()
  119. res=func(*args,**kwargs)
  120. return res
  121. return wrapper
  122.  
  123. @auth
  124. def index():
  125. time.sleep(random.randrange(3))
  126. print('welcome to index')
  127.  
  128. @auth
  129. def home(name):
  130. time.sleep(random.randrange(3))
  131. print('welcome %s to home ' %name)
  132.  
  133. index()
  134. home('egon')
  135.  
  136. #题目六:
  137. import requests
  138. import os
  139. def wget(url):
  140. res = requests.get(url)
  141. return res
  142. print(wget("http://baidu.com/"))
  143. #题目七:简单版本
  144. import requests
  145. import os
  146. cache_file='cache.txt'
  147. def make_cache(func):
  148. def wrapper(*args,**kwargs):
  149. if not os.path.exists(cache_file):
  150. with open(cache_file,'w'):pass
  151.  
  152. if os.path.getsize(cache_file):
  153. with open(cache_file,'r',encoding='utf-8') as f:
  154. res=f.read()
  155. else:
  156. res=func(*args,**kwargs)
  157. with open(cache_file,'w',encoding='utf-8') as f:
  158. f.write(res)
  159. return res
  160. return wrapper
  161.  
  162. @make_cache
  163. def get(url):
  164. return requests.get(url).text
  165.  
  166. # res=get('https://www.python.org')
  167.  
  168. # print(res)
  169.  
  170. #题目七:扩展版本
  171. import requests,os,hashlib
  172. engine_settings={
  173. 'file':{'dirname':'./db'},
  174. 'mysql':{
  175. 'host':'127.0.0.1',
  176. 'port':3306,
  177. 'user':'root',
  178. 'password':''},
  179. 'redis':{
  180. 'host':'127.0.0.1',
  181. 'port':6379,
  182. 'user':'root',
  183. 'password':''},
  184. }
  185.  
  186. def make_cache(engine='file'):
  187. if engine not in engine_settings:
  188. raise TypeError('egine not valid')
  189. def deco(func):
  190. def wrapper(url):
  191. if engine == 'file':
  192. m=hashlib.md5(url.encode('utf-8'))
  193. cache_filename=m.hexdigest()
  194. cache_filepath=r'%s/%s' %(engine_settings['file']['dirname'],cache_filename)
  195.  
  196. if os.path.exists(cache_filepath) and os.path.getsize(cache_filepath):
  197. return open(cache_filepath,encoding='utf-8').read()
  198.  
  199. res=func(url)
  200. with open(cache_filepath,'w',encoding='utf-8') as f:
  201. f.write(res)
  202. return res
  203. elif engine == 'mysql':
  204. pass
  205. elif engine == 'redis':
  206. pass
  207. else:
  208. pass
  209.  
  210. return wrapper
  211. return deco
  212.  
  213. @make_cache(engine='file')
  214. def get(url):
  215. return requests.get(url).text
  216.  
  217. # print(get('https://www.python.org'))
  218. print(get('https://www.baidu.com'))
  219.  
  220. #题目八
  221. route_dic={}
  222.  
  223. def make_route(name):
  224. def deco(func):
  225. route_dic[name]=func
  226. return deco
  227. @make_route('select')
  228. def func1():
  229. print('select')
  230.  
  231. @make_route('insert')
  232. def func2():
  233. print('insert')
  234.  
  235. @make_route('update')
  236. def func3():
  237. print('update')
  238.  
  239. @make_route('delete')
  240. def func4():
  241. print('delete')
  242.  
  243. print(route_dic)
  244.  
  245. #题目九
  246. import time
  247. import os
  248.  
  249. def logger(logfile):
  250. def deco(func):
  251. if not os.path.exists(logfile):
  252. with open(logfile,'w'):pass
  253.  
  254. def wrapper(*args,**kwargs):
  255. res=func(*args,**kwargs)
  256. with open(logfile,'a',encoding='utf-8') as f:
  257. f.write('%s %s run\n' %(time.strftime('%Y-%m-%d %X'),func.__name__))
  258. return res
  259. return wrapper
  260. return deco
  261.  
  262. @logger(logfile='aaaaaaaaaaaaaaaaaaaaa.log')
  263. def index():
  264. print('index')
  265.  
  266. index()

二 迭代器和生成器

2.1 迭代器

一 迭代的概念

  1. #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值
  2. while True: #只是单纯地重复,因而不是迭代
  3. print('===>')
  4.  
  5. l=[1,2,3]
  6. count=0
  7. while count < len(l): #迭代
  8. print(l[count])
  9. count+=1

二 为何要有迭代器?什么是可迭代对象?什么是迭代器对象?

  1. #1、为何要有迭代器?
  2. 对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
  3.  
  4. #2、什么是可迭代对象?
  5. 可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
  6. 'hello'.__iter__
  7. (1,2,3).__iter__
  8. [1,2,3].__iter__
  9. {'a':1}.__iter__
  10. {'a','b'}.__iter__
  11. open('a.txt').__iter__
  12.  
  13. #3、什么是迭代器对象?
  14. 可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
  15. 而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
  16.  
  17. 文件类型是迭代器对象
  18. open('a.txt').__iter__()
  19. open('a.txt').__next__()
  20.  
  21. #4、注意:
  22. 迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象

三 迭代器对象的使用

  1. dic={'a':1,'b':2,'c':3}
  2. iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身
  3. iter_dic.__iter__() is iter_dic #True
  4.  
  5. print(iter_dic.__next__()) #等同于next(iter_dic)
  6. print(iter_dic.__next__()) #等同于next(iter_dic)
  7. print(iter_dic.__next__()) #等同于next(iter_dic)
  8. # print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志
  9.  
  10. #有了迭代器,我们就可以不依赖索引迭代取值了
  11. iter_dic=dic.__iter__()
  12. while 1:
  13. try:
  14. k=next(iter_dic)
  15. print(dic[k])
  16. except StopIteration:
  17. break
  18.  
  19. #这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环

四 for循环

  1. #基于for循环,我们可以完全不再依赖索引去取值了
  2. dic={'a':1,'b':2,'c':3}
  3. for k in dic:
  4. print(dic[k])
  5.  
  6. #for循环的工作原理
  7. #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
  8. #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
  9. #3: 重复过程2,直到捕捉到异常StopIteration,结束循环

五 迭代器的优缺点

  1. #优点:
  2. - 提供一种统一的、不依赖于索引的迭代方式
  3. - 惰性计算,节省内存
  4. #缺点:
  5. - 无法获取长度(只有在next完毕才知道到底有几个值)
  6. - 一次性的,只能往后走,不能往前退

2.2 生成器

一 什么是生成器

  1. #只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
  2.  
  3. def func():
  4. print('====>first')
  5. yield 1
  6. print('====>second')
  7. yield 2
  8. print('====>third')
  9. yield 3
  10. print('====>end')
  11.  
  12. g=func()
  13. print(g) #<generator object func at 0x0000000002184360>

二 生成器就是迭代器

  1. g.__iter__
  2. g.__next__
  3. #2、所以生成器就是迭代器,因此可以这么取值
  4. res=next(g)
  5. print(res)

三 练习

1、自定义函数模拟range(1,7,2)

2、模拟管道,实现功能:tail -f access.log | grep '404'

  1. #题目一:
  2. def my_range(start,stop,step=1):
  3. while start < stop:
  4. yield start
  5. start+=step
  6.  
  7. #执行函数得到生成器,本质就是迭代器
  8. obj=my_range(1,7,2) #1 3 5
  9. print(next(obj))
  10. print(next(obj))
  11. print(next(obj))
  12. print(next(obj)) #StopIteration
  13.  
  14. #应用于for循环
  15. for i in my_range(1,7,2):
  16. print(i)
  17.  
  18. #题目二
  19. import time
  20. def tail(filepath):
  21. with open(filepath,'rb') as f:
  22. f.seek(0,2)
  23. while True:
  24. line=f.readline()
  25. if line:
  26. yield line
  27. else:
  28. time.sleep(0.2)
  29.  
  30. def grep(pattern,lines):
  31. for line in lines:
  32. line=line.decode('utf-8')
  33. if pattern in line:
  34. yield line
  35.  
  36. for line in grep('',tail('access.log')):
  37. print(line,end='')
  38.  
  39. #测试
  40. with open('access.log','a',encoding='utf-8') as f:
  41. f.write('出错啦404\n')

四 协程函数

  1. #yield关键字的另外一种使用形式:表达式形式的yield
  2. def eater(name):
  3. print('%s 准备开始吃饭啦' %name)
  4. food_list=[]
  5. while True:
  6. food=yield food_list
  7. print('%s 吃了 %s' % (name,food))
  8. food_list.append(food)
  9.  
  10. g=eater('egon')
  11. g.send(None) #对于表达式形式的yield,在使用时,第一次必须传None,g.send(None)等同于next(g)
  12. g.send('蒸羊羔')
  13. g.send('蒸鹿茸')
  14. g.send('蒸熊掌')
  15. g.send('烧素鸭')
  16. g.close()
  17. g.send('烧素鹅')
  18. g.send('烧鹿尾')

五 练习
1、编写装饰器,实现初始化协程函数的功能

2、实现功能:grep  -rl  'python'  /etc

  1. #题目一:
  2. def init(func):
  3. def wrapper(*args,**kwargs):
  4. g=func(*args,**kwargs)
  5. next(g)
  6. return g
  7. return wrapper
  8. @init
  9. def eater(name):
  10. print('%s 准备开始吃饭啦' %name)
  11. food_list=[]
  12. while True:
  13. food=yield food_list
  14. print('%s 吃了 %s' % (name,food))
  15. food_list.append(food)
  16.  
  17. g=eater('egon')
  18. g.send('蒸羊羔')
  19.  
  20. #题目二:
  21. #注意:target.send(...)在拿到target的返回值后才算执行结束
  22. import os
  23. def init(func):
  24. def wrapper(*args,**kwargs):
  25. g=func(*args,**kwargs)
  26. next(g)
  27. return g
  28. return wrapper
  29.  
  30. @init
  31. def search(target):
  32. while True:
  33. filepath=yield
  34. g=os.walk(filepath)
  35. for dirname,_,files in g:
  36. for file in files:
  37. abs_path=r'%s\%s' %(dirname,file)
  38. target.send(abs_path)
  39. @init
  40. def opener(target):
  41. while True:
  42. abs_path=yield
  43. with open(abs_path,'rb') as f:
  44. target.send((f,abs_path))
  45. @init
  46. def cat(target):
  47. while True:
  48. f,abs_path=yield
  49. for line in f:
  50. res=target.send((line,abs_path))
  51. if res:
  52. break
  53. @init
  54. def grep(pattern,target):
  55. tag=False
  56. while True:
  57. line,abs_path=yield tag
  58. tag=False
  59. if pattern.encode('utf-8') in line:
  60. target.send(abs_path)
  61. tag=True
  62. @init
  63. def printer():
  64. while True:
  65. abs_path=yield
  66. print(abs_path)
  67.  
  68. g=search(opener(cat(grep('你好',printer()))))
  69. # g.send(r'E:\CMS\aaa\db')
  70. g=search(opener(cat(grep('python',printer()))))
  71. g.send(r'E:\CMS\aaa\db')

六 yield总结

  1. #1、把函数做成迭代器
  2. #2、对比return,可以返回多次值,可以挂起/保存函数的运行状态

2.3 面向过程编程

  1. #1、首先强调:面向过程编程绝对不是用函数编程这么简单,面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序
  2.  
  3. #2、定义
  4. 面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么
  5.  
  6. 基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式
  7.  
  8. #3、优点:复杂的问题流程化,进而简单化
  9.  
  10. #4、缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身
  11.  
  12. #5、应用:扩展性要求不高的场景,典型案例如linux内核,git,httpd
  13.  
  14. #6、举例
  15. 流水线1
  16. 用户输入用户名、密码--->用户验证--->欢迎界面
  17.  
  18. 流水线2
  19. 用户输入sql--->sql解析--->执行功能

三 三元表达式、列表推导式、生成器表达式

3.1 三元表达式

  1. name=input('姓名>>: ')
  2. res='SB' if name == 'alex' else 'NB'
  3. print(res)

3.2 列表推导式

  1. #1、示例
  2. egg_list=[]
  3. for i in range(10):
  4. egg_list.append('鸡蛋%s' %i)
  5.  
  6. egg_list=['鸡蛋%s' %i for i in range(10)]
  7.  
  8. #2、语法
  9. [expression for item1 in iterable1 if condition1
  10. for item2 in iterable2 if condition2
  11. ...
  12. for itemN in iterableN if conditionN
  13. ]
  14. 类似于
  15. res=[]
  16. for item1 in iterable1:
  17. if condition1:
  18. for item2 in iterable2:
  19. if condition2
  20. ...
  21. for itemN in iterableN:
  22. if conditionN:
  23. res.append(expression)
  24.  
  25. #3、优点:方便,改变了编程习惯,可称之为声明式编程

3.3 生成器表达式

  1. #1、把列表推导式的[]换成()就是生成器表达式
  2.  
  3. #2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
  4. >>> chicken=('鸡蛋%s' %i for i in range(5))
  5. >>> chicken
  6. <generator object <genexpr> at 0x10143f200>
  7. >>> next(chicken)
  8. '鸡蛋0'
  9. >>> list(chicken) #因chicken可迭代,因而可以转成列表
  10. ['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4',]
  11.  
  12. #3、优点:省内存,一次只产生一个值在内存中

3.4 练习

1、将names=['egon','alex_sb','wupeiqi','yuanhao']中的名字全部变大写

2、将names=['egon','alex_sb','wupeiqi','yuanhao']中以sb结尾的名字过滤掉,然后保存剩下的名字长度

3、求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)

4、求文件a.txt中总共包含的字符个数?思考为何在第一次之后的n次sum求和得到的结果为0?(需要使用sum函数)

5、思考题

  1. with open('a.txt') as f:
  2. g=(len(line) for line in f)
  3. print(sum(g)) #为何报错?

6、文件shopping.txt内容如下

求总共花了多少钱?

打印出所有商品的信息,格式为[{'name':'xxx','price':333,'count':3},...]

求单价大于10000的商品信息,格式同上

  1. #题目一
  2. names=['egon','alex_sb','wupeiqi','yuanhao']
  3. names=[name.upper() for name in names]
  4.  
  5. #题目二
  6. names=['egon','alex_sb','wupeiqi','yuanhao']
  7. names=[len(name) for name in names if not name.endswith('sb')]
  8.  
  9. #题目三
  10. with open('a.txt',encoding='utf-8') as f:
  11. print(max(len(line) for line in f))
  12.  
  13. #题目四
  14. with open('a.txt', encoding='utf-8') as f:
  15. print(sum(len(line) for line in f))
  16. print(sum(len(line) for line in f)) #求包换换行符在内的文件所有的字符数,为何得到的值为0?
  17. print(sum(len(line) for line in f)) #求包换换行符在内的文件所有的字符数,为何得到的值为0?
  18.  
  19. #题目五(略)
  20.  
  21. #题目六:每次必须重新打开文件或seek到文件开头,因为迭代完一次就结束了
  22. with open('a.txt',encoding='utf-8') as f:
  23. info=[line.split() for line in f]
  24. cost=sum(float(unit_price)*int(count) for _,unit_price,count in info)
  25. print(cost)
  26.  
  27. with open('a.txt',encoding='utf-8') as f:
  28. info=[{
  29. 'name': line.split()[0],
  30. 'price': float(line.split()[1]),
  31. 'count': int(line.split()[2]),
  32. } for line in f]
  33. print(info)
  34.  
  35. with open('a.txt',encoding='utf-8') as f:
  36. info=[{
  37. 'name': line.split()[0],
  38. 'price': float(line.split()[1]),
  39. 'count': int(line.split()[2]),
  40. } for line in f if float(line.split()[1]) > 10000]
  41. print(info)

四 json & pickle 模块

之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。

  1. import json
  2. x="[null,true,false,1]"
  3. print(eval(x)) #报错,无法解析null类型,而json就可以
  4. print(json.loads(x))

什么是序列化?

我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

为什么要序列化?

1:持久保存状态

需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状态'会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。

内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。

在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。

具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。

2:跨平台数据交互

序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。

反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

如何序列化之json和pickle:

json

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

  1. import json
  2.  
  3. dic={'name':'alvin','age':23,'sex':'male'}
  4. print(type(dic))#<class 'dict'>
  5.  
  6. j=json.dumps(dic)
  7. print(type(j))#<class 'str'>
  1. json.dump(obj,文件对象(w方式))
  1. json.load(文件对象(r模式)
  1.  
  2. f=open('序列化对象','w')
  3. f.write(j) #-------------------等价于json.dump(dic,f)
  4. f.close()
  5. #-----------------------------反序列化<br>
  6. import json
  7. f=open('序列化对象')
  8. data=json.loads(f.read())# 等价于data=json.load(f)

pickle

  1. import pickle
  2.  
  3. dic={'name':'alvin','age':23,'sex':'male'}
  4.  
  5. print(type(dic))#<class 'dict'>
  6.  
  7. j=pickle.dumps(dic)
  8. print(type(j))#<class 'bytes'>
  9.  
  10. f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j'bytes'
  11. f.write(j) #-------------------等价于pickle.dump(dic,f)
  12.  
  13. f.close()
  14. #-------------------------反序列化
  15. import pickle
  16. f=open('序列化对象_pickle','rb')
  17.  
  18. data=pickle.loads(f.read())# 等价于data=pickle.load(f)
  19.  
  20. print(data['age'])

Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

Day4 装饰器——迭代器——生成器的更多相关文章

  1. day4装饰器-迭代器&&生成器

    一.装饰器 定义:本质是函数,(装饰其他函数)就是为其它函数添加附加功能 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 实现装饰器知识储备: 1.函数及“变量” 2.高阶 ...

  2. python中的装饰器迭代器生成器

    装饰器: 定义:本质是函数(装饰其它函数) 为其它函数添加附加功能 原则: 1 不能修改被装饰函数源代码    2 不修改被装饰函数调用方式 实现装饰器知识储备: 1 函数即‘’变量‘’ 2 高阶函数 ...

  3. Python学习---装饰器/迭代器/生成器的学习【all】

    Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210

  4. day04 装饰器 迭代器&生成器 Json & pickle 数据序列化 内置函数

    回顾下上次的内容 转码过程: 先decode  为 Unicode(万国码 ) 然后encode 成需要的格式     3.0 默认是Unicode  不是UTF-8 所以不需要指定  如果非要转为U ...

  5. python_装饰器——迭代器——生成器

    一.装饰器 1.什么是装饰器? 器=>工具,装饰=>增加功能 1.不修改源代码 2.不修改调用方式 装饰器是在遵循1和2原则的基础上为被装饰对象增加功能的工具 2.实现无参装饰器 1.无参 ...

  6. python装饰器,迭代器,生成器,协程

    python装饰器[1] 首先先明白以下两点 #嵌套函数 def out1(): def inner1(): print(1234) inner1()#当没有加入inner时out()不会打印输出12 ...

  7. python笔记3 闭包 装饰器 迭代器 生成器 内置函数 初识递归 列表推导式 字典推导式

    闭包 1, 闭包是嵌套在函数中的 2, 闭包是内层函数对外层函数的变量(非全局变量)的引用(改变) 3,闭包需要将其作为一个对象返回,而且必须逐层返回,直至最外层函数的返回值 闭包例子: def a1 ...

  8. Python中的装饰器,迭代器,生成器

    1. 装饰器 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象. 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的 ...

  9. 装饰器、生成器,迭代器、Json & pickle 数据序列化

    1. 列表生成器:代码例子 a=[i*2 for i in range(10)] print(a) 运行效果如下: D:\python35\python.exe D:/python培训/s14/day ...

随机推荐

  1. expander graph&random walk的一个小应用

    此文主要总结的是一种随机算法,旨在判断一个expander图上两点是否连通.复杂度O(logn).算法思路清奇. expander graph博大精深,如果对expander graph的生成,fam ...

  2. hr用法

    定义和用法 <hr> 标签在 HTML 页面中创建一条水平线. 水平分隔线(horizontal rule)可以在视觉上将文档分隔成各个部分. HTML 与 XHTML 之间的差异 在 H ...

  3. webpack教程(六)——分离组件代码

    先来运行一下webpack命令, 看到app.js才4k. 安装一下react npm install react --sava-dev 在app/index.js文件内引入react 运行webpa ...

  4. Centos7.2下Nginx配置SSL支持https访问(站点是基于.Net Core2.0开发的WebApi)

    准备工作 1.基于nginx部署好的站点(本文站点是基于.Net Core2.0开发的WebApi,有兴趣的同学可以跳http://www.cnblogs.com/GreedyL/p/7422796. ...

  5. 可编辑的EditorGridPanel

    1.创建pannel是为可编辑的: new Ext.grid.EditorGridPanel 2.设置单击可以编辑属性: clickstoEdit: 1 3.在列设置添加文本编辑框 {header:& ...

  6. postman 第1节 安装启动(转)

    安装: 1.mac app安装 浏览器访问https://www.getpostman.com/apps,选择Get the Mac App,下载安装即可 2.chrome app安装 浏览器访问ht ...

  7. Spring上传文件,图片,以及常见的问题

    1. 在工程依赖库下添加文件上传jar包 commons-fileupload-1.2.2.jar commons-io-2.4.jar 2.在springMVC配置文件中配置视图解析multipar ...

  8. nginx小问题

    配置nginx与ftp图片服务器:安装后,要在/usr/local/nginx/conf/nginx.conf里面的server中(带有localhost的那一块)修改为location \ {roo ...

  9. string和double之间的相互转换(C++)

    很多人都写过这个标题的文章,但本文要解决的是确保负数的string和double也可以进行转换. 代码如下: string转double double stringToDouble(string nu ...

  10. 软件工程(GZSD2015)第三次作业提交进度

    第三次作业题目请查看这里:软件工程(GZSD2015)第三次作业 开始进入第三次作业提交进度记录中,童鞋们,虚位以待哈... 2015年4月19号 徐镇.尚清丽,C语言 2015年4月21号 毛涛.徐 ...