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函数对象

 

posted on 2017-06-07 21:27  Tigercoll  阅读(383)  评论(0)    收藏  举报