闭包现象
正常来说, 函数调用结束, 函数体里的变量都会被销毁, 而有一种现象是当函数执行完毕, 函数体里的变量不会被销毁, 因为这个变量被内嵌函数的一段代码调用着, 无法销毁, 这种现象叫做闭包
- def outer():
- name='周泽 SB'
- def inner():
- print(name)
- return inner
- func_inner=outer() # 返回的是 inner 这个内层函数对象加上调用的变量 name 的作用域
- func_inner()
闭包函数的一种, 主要场景是一段程序执行前需要判断是否是否登录
实现这个功能还要符合开放封闭原则 ( 不改变程序的源代码以及调用方式进行扩展)
源程序
- def home():
- print('主页')
- def america():
- print('---- 欧美专区 ----')
- def japan():
- print('---- 日韩专区 ----')
- home()
- america()
- japan()
初级版
需要对 america, japan 加入登录验证
- account = {
- 'is_authenticated': False,
- 'username': 'zzsb',
- 'password': '123',
- }
- def login(func):
- if not account['is_authenticated']:
- usr, pwd = input('请输入用户名').strip(), input('请输入密码').strip()
- username, password = account.get('username'), account.get('password')
- if usr == username and pwd == password:
- print('登入成功')
- account['is_authenticated'] = True
- return func
- else:
- print('用户名或密码错误')
- else:
- print('用户已登录, 认证通过')
- return func
- def home():
- print('主页')
- def america():
- print('---- 欧美专区 ----')
- def japan():
- print('---- 日韩专区 ----')
- america = login(america)
- america()
- japan = login(japan)
- japan()
使用闭包函数实现功能(装饰器的本质)
- account = {
- 'is_authenticated': False,
- 'username': 'zzsb',
- 'password': '123',
- }
- def login(func):
- def inner():
- if not account['is_authenticated']:
- usr, pwd = input('请输入用户名').strip(), input('请输入密码').strip()
- username, password = account.get('username'), account.get('password')
- if usr == username and pwd == password:
- print('登入成功')
- account['is_authenticated'] = True
- func()
- else:
- print('用户名或密码错误')
- else:
- print('用户已登录, 认证通过')
- func()
- return inner
- def home():
- print('主页')
- def america():
- print('---- 欧美专区 ----')
- def japan():
- print('---- 日韩专区 ----')
- america = login(america)
- america()
- japan = login(japan)
- japan()
高级版
如果被要求登录认证的函数是有参数的, 上面的代码就会报错
- account = {
- 'is_authenticated': False,
- 'username': 'zzsb',
- 'password': '123',
- }
- def login(func):
- def inner(*args,**kwargs):
- if not account['is_authenticated']:
- usr, pwd = input('请输入用户名').strip(), input('请输入密码').strip()
- username, password = account.get('username'), account.get('password')
- if usr == username and pwd == password:
- print('登入成功')
- account['is_authenticated'] = True
- func(*args,**kwargs)
- else:
- print('用户名或密码错误')
- else:
- print('用户已登录, 认证通过')
- func(*args,**kwargs)
- return inner
- def home():
- print('主页')
- def america():
- print('---- 欧美专区 ----')
- def japan(vip_level):
- if vip_level> 3:
- print('解锁高级玩法')
- else:
- print('---- 日韩专区 ----')
- america = login(america)
- america()
- japan = login(japan)
- japan(4)
python 装饰器用法
在需要进行登录验证的函数上加上 @装饰器函数
- account = {
- 'is_authenticated': False,
- 'username': 'zzsb',
- 'password': '123',
- }
- def login(func):
- def inner(*args,**kwargs):
- if not account['is_authenticated']:
- usr, pwd = input('请输入用户名').strip(), input('请输入密码').strip()
- username, password = account.get('username'), account.get('password')
- if usr == username and pwd == password:
- print('登入成功')
- account['is_authenticated'] = True
- func(*args,**kwargs)
- else:
- print('用户名或密码错误')
- else:
- print('用户已登录, 认证通过')
- func(*args,**kwargs)
- return inner
- def home():
- print('主页')
- @login
- def america():
- print('---- 欧美专区 ----')
- @login
- def japan(vip_level):
- if vip_level> 3:
- print('解锁高级玩法')
- else:
- print('---- 日韩专区 ----')
- america()
- japan(4)
列表生成式
将列表的值的元素每一个加 1
使用 lambda 函数
- a = [1, 2, 3, 4, 5]
- res = map(lambda x: x + 1, a)
- print(list(res))
使用列表生成式
- a = [1, 2, 3, 4, 5]
- ls = [i+1 for i in a]
- print(ls)
生成器
range 在 python2 和 python3 的区别
python2 环境下自动生成数字存入对象
- >>> range(10)
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
python3 中只是一个生成器对象
- >>> range(10)
- range(0, 10)
引子
for 循环生成 100000000 个数字
- import time
- start= time.time()
- for i in range(100000000):
- if i == 100:
- break
- print(i)
- print(time.time()-start) # 2.91226005554
while 循环生成 100000000 个数字
- import time
- start = time.time()
- count = 0
- while count <100000000:
- count += 1
- if count> 100:
- break
- print(time.time() - start) # 0.000188112258911
什么是生成器
以上 2 个例子:
for 循环执行效率更慢, 因为先生成 1-100000000 的列表, 再进行判断, 这种占用大量内存空间
while 循环是通过某种算法 ( 每次自加 1) 计算出下一次循环的数据, 根据需要进行取值, 这种占用内存更少
在 python 中, 这种一边循环一边计算下一次循环的值的机制就是生成器, 也可理解为一种数据类型
创建生成器
- >>> (x*x for x in range(10))
- <generator object <genexpr> at 0x10ddf5a50>
生成器取值
通过 next 取值
- >>> test=(x*x for x in range(5))
- >>> test
- <generator object <genexpr> at 0x103979d58>
- >>> next(test)
- 0
- >>> next(test)
- 1
- >>> next(test)
- 4
- >>> next(test)
- 9
- >>> next(test)
- 16
- >>> next(test) # 取不到值就会报错
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- StopIteration
取出所有值
- >>> test=(x*x for x in range(5))
- >>> for i in test:
- ... print(i)
- ...
- 0
- 1
- 4
- 9
- 16
函数生成器
实现斐波那契数列
- 1 2 3 5 8 13....
- count = 0
- a = 0
- b = 1
- while count <20:
- old_a = a
- a = b
- b = old_a + a
- '''
- 第一次循环: old_a=0 a=1 b=1
- 第二次循环: old_a=1 a=1 b=2
- 第三次循环: old_a=1 a=2 b=3
- 第四次循环: old_a=2 a=3 b=5
- '''
- print(b)
- count += 1
通过生成器实现斐波那契数列
- def MakeServer(n):
- '''
- 生成器函数
- '''
- count = 0
- a = 0
- b = 1
- while count < n:
- old_a = a
- a = b
- b = old_a + a
- '''
- 第一次循环: old_a=0 a=1 b=1
- 第二次循环: old_a=1 a=1 b=2
- 第三次循环: old_a=1 a=2 b=3
- 第四次循环: old_a=2 a=3 b=5
- '''
- yield b # 暂停并返回 b 的值, 下面的代码通过 next()函数触发才会执行
- count += 1
- obj=MakeServer(6)
- print(obj.__next__())
- print(obj.__next__())
- print(obj.__next__())
- print(obj.__next__())
- print('---- 生成器 ----')
- print(obj.__next__())
- print(obj.__next__())
Yield 接收外部输入的值
错误代码
- TypeError: can't send non-None value to a just-started generator
- def g_test():
- while True:
- n = yield
- print('recieve from outside', n)
- g=g_test()
- for i in range(10):
- g.send(i)
解决方案
先发送一个 None 给到生成器
- def g_test():
- while True:
- n = yield
- print('recieve from outside', n)
- g=g_test()
- g.send(None) # 调用生成器, 同时会发送 None 到 Yield
- for i in range(10):
- g.send(i) # 调用生成器, 同时发送 i
- def g_test():
- while True:
- n = yield
- print('recieve from outside', n)
- g=g_test()
- g.__next__() # 调用生成器, 同时会发送 None 到 Yield
- for i in range(10):
- g.send(i) # 调用生成器, 同时发送 i
实现单线程下的多并发
- def consumer(name):
- print('消费者 %s 准备吃包子了...' % name)
- while True:
- baozi_num = yield
- print('消费者 %s 吃了包子 %s' % (name, baozi_num))
- c1 = consumer('c1')
- c2 = consumer('c2')
- c3 = consumer('c3')
- c1.__next__()
- c2.__next__()
- c3.__next__()
- for i in range(1, 6):
- print('------- 生成了第 %s 批包子 -------' % i)
- c1.send(i)
- c2.send(i)
- c3.send(i)
迭代器
可迭代对象
直接作用于 for 循环的对象统称为可迭代对象 ( 可以被循环 )
判断一个对象是否是 Iterable 对象
- >>> 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 循环
集合类型数据 , list, tuple, dict, set, str 等
generator, 包括生成器和带 yield 的 generator function
什么是迭代器
可以被 next() 函数调用并不断返回下一个值的对象称为迭代器: Iterator
判断一个对象是否是 Iterator
- >>> from collections import Iterator
- >>> isinstance(1,Iterator)
- False
- >>> isinstance({
- },Iterator)
- False
- >>> isinstance([],Iterator)
- False
- >>> isinstance('周泽 SB',Iterator)
- False
- >>> isinstance((i for i in range(10)),Iterator) # 生成器对象是迭代器对象
- True
- >>> iter({
- }) # 可迭代对象通过调用函数 iter()可转换为迭代器对象
- <dict_keyiterator object at 0x10a9ad1d8>
- >>> isinstance(iter({
- }),Iterator)
- True
- >>> isinstance(iter([]),Iterator)
- True
- >>> isinstance(iter('周泽 SB'),Iterator)
- True
函数(二)
来源: http://www.bubuko.com/infodetail-3218487.html