首页 > 代码库 > Python基础(二)
Python基础(二)
?成器
1. 什么是?成器
通过列表?成式,我们可以直接创建?个列表。但是,受到内存限制,列表 容量肯定是有限的。?且,创建?个包含100万个元素的列表,不仅占?很 ?的存储空间,如果我们仅仅需要访问前??个元素,那后?绝?多数元素 占?的空间都??浪费了。所以,如果列表元素可以按照某种算法推算出 来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必 创建完整的list,从?节省?量的空间。在Python中,这种?边循环?边计算 的机制,称为?成器:generator。
2. 创建?成器?法1
要创建?个?成器,有很多种?法。第?种?法很简单,只要把?个列表? 成式的 [ ] 改成 ( )
输入:L=[ x*2 for x in range(5)] 输出:print(L) 结果:[0, 2, 4, 6, 8] 输入:G=(x *2 for x in range(5)) 输出:print (G) 结果:<generator object <genexpr> at 0x03490EA0>
创建 L 和 G 的区别仅在于最外层的 [ ] 和 ( ) , L 是?个列表,? G 是?个 ?成器。我们可以直接打印出L的每?个元素,但我们怎么打印出G的每?个 元素呢?如果要?个?个打印出来,可以通过 next() 函数获得?成器的下? 个返回值:
G=(x *2 for x in range(5)) print(next(G)) print(next(G)) print(next(G)) 0 2 4
G=(x *2 for x in range(5)) for i in G: print(i) 0 2 4 6 8
?成器保存的是算法,每次调? next(G) ,就计算出 G 的下?个元素的值, 直到计算到最后?个元素,没有更多的元素时,抛出 StopIteration 的异常。 当然,这种不断调? next() 实在是太变态了,正确的?法是使? for 循环, 因为?成器也是可迭代对象。所以,我们创建了?个?成器后,基本上永远 不会调? next() ,?是通过 for 循环来迭代它,并且不需要关? StopIteration 异常。
总结
?成器是这样?个函数,它记住上?次返回时在函数体中的位置。对?成器 函数的第?次(或第 n 次)调?跳转?该函数中间,?上次调?的所有局部 变量都保持不变。
?成器不仅“记住”了它数据状态;?成器还“记住”了它在流控制构造(在命令 式编程中,这种构造不只是数据值)中的位置。
?成器的特点:
1. 节约内存
2. 迭代到下?次的调?时,所使?的参数都是第?次所保留下的,即是 说,在整个所有函数调?的参数都是第?次所调?时保留的,?不是新 创建的
迭代器
迭代是访问集合元素的?种?式。迭代器是?个可以记住遍历的位置的对 象。迭代器对象从集合的第?个元素开始访问,直到所有的元素被访问完结 束。迭代器只能往前不会后退。
1. 可迭代对象
以直接作?于 for 循环的数据类型有以下?种:
?类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
?类是 generator ,包括?成器和带 yield 的generator function。
这些可以直接作?于 for 循环的对象统称为可迭代对象: Iterable 。
2. 判断是否可以迭代
可以使? isinstance() 判断?个对象是否是 Iterable 对象:
总结
凡是可作?于 for 循环的对象都是 Iterable 类型;
凡是可作?于 next() 函数的对象都是 Iterator 类型
集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可 以通过 iter() 函数获得?个 Iterator 对象。
装饰器
装饰器是程序开发中经常会?到的?个功能,?好了装饰器,开发效率如? 添翼,所以这也是Python?试中必问的问题,但对于好多初次接触这个知识 的?来讲,这个功能有点绕,?学时直接绕过去了,然后?试问到了就挂 了,因为装饰器是程序开发的基础知识,这个都不会,别跟?家说你会 Python, 看了下?的?章,保证你学会装饰器。
初创公司有N个业务部?,1个基础平台部?,基础平台负责提供底层的功 能,如:数据库操作、redis调?、监控API等功能。业务部?使?基础功能 时,只需调?基础平台提供的功能即可。如下:
def f1(): print(‘f1‘) def f2(): print(‘f2‘) def f3(): print(‘f3‘) def f4(): print(‘f4‘)
############### 业务部?A 调?基础平台提供的功能 ############### f1() f2() f3() f4() ############### 业务部?B 调?基础平台提供的功能 ###############
f1() f2() f3() f4()
?前公司有条不紊的进?着,但是,以前基础平台的开发?员在写代码时候 没有关注验证相关的问题,
即:基础平台的提供的功能可以被任何?使?。 现在需要对基础平台的所有功能进?重构,为平台提供的所有功能添加验证 机制,即:执?功能前,先进?验证。
??把?作交给 Low B,他是这么做的:
跟每个业务部?交涉,每个业务部???写代码,调?基础平台的功能 之前先验证。诶,这样?来基础平台就不需要做任何修改了。太棒了, 有充?的时间泡妹?...
当天Low B 被开除了…
??把?作交给 Low BB,他是这么做的:
############### 基础平台提供的功能如下 ###############
def f1(): # 验证1 # 验证2 # 验证3 print (‘f1‘) def f2(): # 验证1 # 验证2 # 验证3 print (‘f2‘) def f3(): # 验证1 # 验证2 # 验证3 print (‘f3‘) def f4(): # 验证1 # 验证2 # 验证3 print (‘f4‘)
############### 业务部?不变 ############### ### 业务部?A 调?基础平台提供的功能###
过了?周 Low BB 被开除了…
??把?作交给 Low BBB,他是这么做的:
只对基础平台的代码进?重构,其他业务部??需做任何修改 ############### 基础平台提供的功能如下 ############### def check_login():
# 验证1
# 验证2
# 验证3
pass def f1(): check_login() print(‘f1‘) def f2(): check_login() print(‘f2‘) def f3(): check_login() print(‘f3‘) def f4(): check_login() print(‘f4‘)
??看了下Low BBB 的实现,嘴?漏出了?丝的欣慰的笑,语重??的跟 Low BBB聊了个天:
??说:
写代码要遵循 开放封闭 原则,虽然在这个原则是?的?向对象开发,但是也 适?于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改, 但可以被扩展,即:
封闭:已实现的功能代码块
开放:对扩展开发
如果将开放封闭原则应?在上述需求中,那么就不允许在函数 f1 、f2、f3、 f4的内部进?修改代码,?板就给了Low BBB?个实现?案:
def w1(func): def inner(): # 验证1 # 验证2 # 验证3 func() return inner @w1 def f1(): print (‘f1‘) @w1 def f2(): print (‘f2‘) @w1 def f3(): print (‘f3‘) @w1 def f4(): print (‘f4‘)
对于上述代码,也是仅仅对基础平台的代码进?修改,就可以实现在其他? 调?函数 f1 f2 f3 f4 之前都进?【验证】操作,并且其他业务部??需做任 何操作。
Low BBB?惊胆战的问了下,这段代码的内部执?原理是什么呢?
??正要??,突然Low BBB的?机掉到地上,恰巧屏保就是Low BBB的? 友照?,???看?紧?抖,喜笑颜开,决定和Low BBB交个好朋友。
详细的开始讲解了:
单独以f1为例:
def w1(func): def inner(): #验证1 #验证2 #验证3 func() return inner @w1 def f1(): print(‘f1‘)
python解释器就会从上到下解释代码,步骤如下:
1. def w1(func): ==>将w1函数加载到内存
2. @w1
没错,从表?上看解释器仅仅会解释这两句代码,因为函数在 没有被调?之 前其内部代码不会被执?。
从表?上看解释器着实会执?这两句,但是 @w1这?句代码?却有??章,@函数名是python的?种语法糖。
上例@w1内部会执??下操作: 执?w1函数
执?w1函数,并将@w1下?的函数作为w1函数的参数,即:@w1 等价于w1(f1)所以,内部就会去执?: def inner(): #验证 1 # #验证 2 # #验证 3 f1() #func是参数,此时func等于f1 return inner #返回的inner,inner代表的是函数,?执?函数,其实就是将原来的f1函数塞进另外?个函数中 w1的返回值 将执?完的w1函数返回值赋值给@w1下?的函数的函数名f1即将w1 的返回值再重新赋值给f1,即: 新f1 = def inner():
# 验证 1 # #验证 2 # #验证 3 原来f1() return inner 所以,以后业务部?想要执?f1函数时,就会执?新f1函数,在新f1 函数内部先执?验证,再执?原来的f1函数,然后将原来f1 函数的返回 值返回给了业务调?者。 如此?来,即执?了验证的功能,?执?了原来f1函数的内容,并将原f1函 数返回值返回给业务调?着 LowBBB 你明?了吗?要是没明?的话,我晚上去你家帮你解决吧!!!
3. 再议装饰器
#定义函数:完成包裹数据 def makeBold(fn): def wrapped(): return "<b>" + fn() + "</b>" return wrapped #定义函数:完成包裹数据 def makeItalic(fn): def wrapped(): return "<i>" + fn() + "</i>" return wrapped @makeBold def test1(): return "hello world-1" @makeItalic def test2(): return "hello world-2" @makeBold @makeItalic def test3(): return "hello world-3" print(test1())) print(test2())) print(test3())) 运?结果: <b>hello world-1</b> <i>hello world-2</i> <b><i>hello world-3</i></b>
4. 装饰器(decorator)功能
1. 引??志
2. 函数执?时间统计
3. 执?函数前预备处理
4. 执?函数后清理功能
5. 权限校验等场景
6. 缓存
5. 装饰器示例
例1:?参数的函数
from time import ctime, sleep def timefun(func): def wrappedfunc(): print ("%s called at %s" % (func.__name__, ctime ())) func () return wrappedfunc @timefun def foo(): print ("I am foo") foo () sleep (2) foo ()
上面代码理解装饰器执行行为可理解成
foo = timefun(foo)
#foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfuncfoo()
#调?foo(),即等价调?wrappedfunc() #内部函数wrappedfunc被引?,所以外部函数的func变量(?由变量)并没有释放
#func?保存的是原foo函数对象
Python基础(二)