您的位置:首页 > 编程语言 > Python开发

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

2016-01-25 23:53 513 查看
迭代器

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

没有值返回,就会引发一个StopIteration异常。

特点:

访问者不需要关心迭代器内部的结构,仅需通过__next__方法不断去取下一个内容

不能随机访问集合中的某个值 ,只能从头到尾依次访问

访问到一半时不能往回退

便于循环比较大的数据集合,节省内存

name = iter(['koka','lolo','lala'])
print(name.__next__())
print(name.__next__())
print(name.__next__())


生成器:

定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(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


生成器方法
生成器的属于表现为生成器和"外部世界"进行沟通交流的渠道注意如下两点:

外部作用域访问生成器的send方法,就像访问__next__方法,send需要一个参数。

在内部则挂起生成器,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')


装饰器:

装饰器的作用就是为已经存在的对象添加额外的功能。装饰器的好处就是在不改变程序源码的前提下,扩展程序功能。

必备知识:

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([code](
*
args,
*
*
kwargs)
):
print("通过验证!!!")
return func(
(
*
args,
*
*
kwargs)
)
return inner

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

#调用过程;
#程序从上往下运行,加载w1函数
#遇见@1,执行w1函数,将f1函数传入到w1函数,
#将执行完的w1函数的返回值赋值给f1 @w1 f1=w1(f1) 此时的f1实际是inner
#调用重新赋值的f1(arg)时,即运行w1函数内部的inner(arg)函数。

详细过程如下:

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

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

@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函数返回值 返回给业务调用者。

递归:

递归即在函数或过程中调用自身;

递归包含如下两个部分:

当函数直接返回值时,有基本实例(最小可能性问题)

递归实例,包括一个或者多个问题最小部分的递归调用

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

递归算法所体现的“重复”一般有三个要求:

每次调用在规模上都有所缩小(通常是减半);

相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);

在问题的可能性极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

阶乘:

* 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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: