python学习笔记四 迭代器,生成器,装饰器(基础篇)

迭代器

  __iter__方法返回一个迭代器,它是具有__next__方法的对象。在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器

没有值返回,就会引发一个StopIteration异常。
 
 特点:
  1. 访问者不需要关心迭代器内部的结构,仅需通过__next__方法不断去取下一个内容
  2. 不能随机访问集合中的某个值 ,只能从头到尾依次访问
  3. 访问到一半时不能往回退
  4. 便于循环比较大的数据集合,节省内存
name = iter(['koka','lolo','lala'])
print(name.__next__())
print(name.__next__())
print(name.__next__())
更多迭代器内容:https://segmentfault.com/a/1190000005915893
 
生成器:
 
    定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),任何包含yied语句的函数称为生成器。生成器是由两部分组成:
生成器的函数和生成器的迭代器。生成器的函数是def语句定义的,包含yield的部分,生成器的迭代器是这个函数返回的部分。
案例一:
def
cash_out(amount): print("欢迎登录ATM") while amount >0: amount -= 1 yield 1 #yield返回一个指定的数 print("欢迎来取钱!") ATM = cash_out(5) print("取到钱 %s 万" % ATM.__next__()) print("花掉花掉!") print("取到钱 %s 万" % ATM.__next__()) print("取到钱 %s 万" % ATM.__next__()) print("花掉花掉!") print("取到钱 %s 万" % ATM.__next__()) print("取到钱 %s 万" % ATM.__next__()) print("取到钱 %s 万" % ATM.__next__()) #到这时钱就取没了,再取就报错了 Traceback (most recent call last): File "D:/home/new.py", line 42, in <module> print("取到钱 %s 万" % ATM.__next__()) #到这时钱就取没了,再取就报错了 StopIteration

 #使用yied语句,函数就会被冻结:即函数停在那点等待被激活。函数被激活后就从停止的那点开始执行。

案例二:
#创建一个嵌套列表的函数,能够顺序打印列表中的数字
li = [[1,2,],[3,4],[5]] def flatten(li): for sublist in li: for item in sublist: yield item #返回子序列中元素的迭代器 for j in flatten(li): print(j) 1
2
3
4
5
生成器方法
生成器的属于表现为生成器和"外部世界"进行沟通交流的渠道注意如下两点:
  1. 外部作用域访问生成器的send方法,就像访问__next__方法,send需要一个参数。
  2. 在内部则挂起生成器,yield作为一个表达式而不是语句,即:当生成器重新运行的时候,yield方法返回值是接受到外部通过send方法发送的值。如果__next__方法被使用yield方法返回None。
#使用yield实现在单线程的情况下实现并发运算的效果

import time
def consumer(name):
    print("%s 准备吃包子!"%name)
    while True:
        baozi = yield
        print("包子[%s]来了,被[%s]吃了!" %(baozi,name)

def producer(name):
    c = consumer('A')
    d = consumer('B')
    c.__next__()
    d.__next__()
    print("开始生产包子!")
    for i in range(5):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        d.send(i)
producer('koka')

更多内容:http://python.jobbole.com/81911/

装饰器:

装饰器其实就是一个以函数作为参数并返回一个替换函数的可执行函数。装饰器的作用就是为已经存在的对象添加额外的功能,使用装饰器可以在不改变程序源码的前提下,扩展程序功能。

必备知识:

def foo():
    print 'foo'

foo     #表示是函数
foo()   #表示执行foo函数

def foo():
    print 'foo'
foo = lambda x: x + 1
foo()    # 执行下面的lambda表达式,而不再是原来的foo函数,因为函数 foo 被重新定义了

普通装饰器

def w1(func):
    def inner(*args,**kwargs):
        print("通过验证!!!")
        return func(*args,**kwargs)
    return inner

@w1
def f1(arg):
    print("欢迎%s来到TV页面" %arg)
f1('abc')

调用过程:

  • 程序从上往下运行,加载w1函数(函数未被执行、未被执行、未被执行);
  • 遇见@w1@函数名 是python的一种语法糖。),执行w1函数,将f1函数传入到w1函数(将 @w1 下面的 函数 作为w1函数的参数,);
  • 将执行完的w1函数的返回值赋值给f1, @w1 <=> f1=w1(f1) 此时的f1实际是inner函数;
  • 调用重新赋值的f1(arg)时,即运行w1函数内部的inner(arg)函数。

详细过程如下:

当写完这段代码后(函数未被执行、未被执行、未被执行),python解释器就会从上到下解释代码,步骤如下:

  1.def w1(func):  ==>将w1函数加载到内存

  2.@w1

没错,从表面上看解释器仅仅会解释这两句代码,因为函数在没有被调用之前其内部代码不会被执行。

从表面上看解释器着实会执行这两句,但是 @w1 这一句代码里却有大文章,@函数名 是python的一种语法糖。

如上例@w1内部会执行一下操作:

  • 执行w1函数,并将 @w1 下面的 函数 作为w1函数的参数,即:@w1 等价于 w1(f1)所以,内部就会去执行:
        def inner(arg):
            #验证
            return f1(arg)   # func是参数,此时 func 等于 f1
        return inner     # 返回的 inner,inner代表的是函数,非执行函数
    其实就是将原来的 f1 函数塞进另外一个函数中
  • 将执行完的 w1 函数返回值赋值给@w1下面的函数的函数名w1函数的返回值是:
       def inner(arg):
            #验证
            return 原来f1(arg)  # 此处的 f1 表示原来的f1函数
    然后,将此返回值再重新赋值给 f1,即:
    新f1 = def inner(arg):

                #验证
                return 原来f1(arg) 
    所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在 新f1 函数内部先执行验证,再执行原来的f1函数,然后将 原来f1 函数的返回值 返回给了业务调用者。
    如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用者。

带参数的装饰器

#!/usr/bin/env python
#coding:utf-8
def Before(request,kargs): print('before') def After(request,kargs): print('after') def Filter(before_func,after_func): def outer(main_func): def wrapper(request,kargs):
Before      
main_result = main_func(request,kargs)
After
return main_result
return wrapper return outer @Filter(Before, After) def Index(request,kargs): print('index') if __name__ == '__main__': Index(1,2)

调用过程:

  • 程序从上往下运行,加载Before,After,Filter函数(函数未被执行、未被执行、未被执行);
  • 遇见@filter(Before,After)@函数名 是python的一种语法糖。),这里会忽略@符号,执行Filter函数,程序从上往下运行,加载outer函数(函数未被执行),将Filter函数的函数值返回给outer;此时表达式 @Filter(Before,After) => @outer 变成了我们熟悉的普通装饰器,
  • 执行outer函数将Index函数传入到outer函数,将执行完的outer函数的返回值赋值给Index, @outer<=> index=outer(index) 此时的index实际是wrapper函数;
  • 调用重新赋值的index(1,2)时,即运行outer函数内部的wrapper(request,kargs)函数。

 

函数不仅可以使用自身的参数,还可以使用装饰器传入的参数。

更多装饰器内容:http://python.jobbole.com/85056/

递归: 

递归即在函数或过程中调用自身;
 
递归包含如下两个部分:
  • 当函数直接返回值时,有基本实例(最小可能性问题)
  • 递归实例,包括一个或者多个问题最小部分的递归调用

这里的关键就是将问题分解为小部分,递归不能永远继续下去,因为它总是以最小可能性问题结束,而这些问题又存储在基本实例中。

递归算法所体现的“重复”一般有三个要求:
  • 每次调用在规模上都有所缩小(通常是减半);
  • 相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
  • 在问题的可能性极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。
阶乘:

    * 1的阶乘是1;
    * 大于1的数n的阶乘是n乘n-1的阶乘

def factorial(n):
     if n == 1:
          return 1
     else:
          return n * factorial(n-1)

阶幂:

    * 对于任何数字x来说,power(x,0)是1;
    * 对于任何大于0的数来说,power(x,n)是x乘以(x,n-1)的结果。

def power(x,n):
     if x == 0:
          return 1
     else:
          return x * power(x,n-1)

查看递归过程:

def cacl(n):
    print(n)
    if n/2 > 1:
        res = cacl(n/2)
        print("res:",res)
    print("N:",n)
    return n
cacl(18)

18
9.0
4.5
2.25
1.125
N: 1.125
res: 1.125
N: 2.25
res: 2.25
N: 4.5
res: 4.5
N: 9.0
res: 9.0
N: 18

递归返回值

def n4():
    return "HAHA"
def n3():
    n4()
def n2():
    n3()
def n1():
    n2()

result = n1()
print result

返回值将是None,执行result = n1(),调用n1函数,n1调用了n2,n1返回None,n2调用n3,n2返回None,n3调用n4,n3返回None  n4返回'HAHA',即使n2-n3中有return n3,return n4 返回值依然是None,因为n1执行的时候返回None.

 二元查找:

def search(data,find_num):
    mid = int( len(data) / 2)
    mid_value = data[mid]
    if len(data) == 1 and data[0] == find_num: #当列表中只有一个数时,判断该数是否存在。

        print("find %s" %find_num)
    elif len(data) >1:
        if mid_value > find_num:
            return search(data[:mid],find_num)
        elif mid_value < find_num:
            return search(data[mid:],find_num)
        else:
            print("find %s" %data[mid])
    else:
        print("cannot find [%s] in data_list" %find_num)
if __name__ == "__main__":
    data = list(range(100))
    search(data,0)

算法:

案例一:
li = [23,52,12,4,7,18,33,99,25]
for i in range(1,len(li)): #循环数组中1到len(li) 1,2,3,4,5...
    for j in range(len(li)-i):#循环数组中len(li)-i到1  ..5,4,3,2,1 每次循环会把最大的值放在最后,然后减少一次循环
        a = li[j]  #列表中第1个值
        b = li[j+1] #列表中第2个值
        if a > b: 
            temp = li[j] #大的值赋给temp
            li[j] = li[j+1] #小的值赋给大的值
            li[j+1] = temp #从temp取出大赋给小的值
print(li)

#同上
案例二:
li2 = [23,52,12,4,7,18,33,99,25]
for i in range(len(li2)-1):
    for j in range(i+1,len(li2)):
        a = li2[i]
        b = li2[j]
        if a > b:
            temp = li2[j]
            li2[j] = li2[i]
            li2[i] = temp
print(li2)

二维数组转换

转换过程如下图:

data = [[i for i in range(4)] for row in range(4)]  #列表推导式创建数据。
for r_index,row in enumerate(data):  #循环行标0,1,2,3 和 data   
    for c_index in range(r_index,len(row)):# 0-4,1-4,2-4
        tmp = data[c_index][r_index]  
        data[c_index][r_index] = data[r_index][c_index] 
        data[r_index][c_index] = tmp
    print('---------------')
    for i in data:print(i)

“”“
data[0][0] = data[0][0] data[1][0] = data[0][1] data[2][0] = data[0][2] data[3][0] = data[0][3]
data[1][1] = data[1][1] data[2][1] = data[1][2] data[3][1] = data[1][3]
data[2][2] = data[2][2] data[3][2] = data[2][3]
data[3][3] = data[3][3]
”“”

结果如下:
[0, 0, 0, 0]
[1, 1, 1, 1]
[2, 2, 2, 2]
[3, 3, 3, 3]

 

posted @ 2016-01-25 23:53  ko_ka24  阅读(307)  评论(0编辑  收藏  举报