迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
names=iter([‘lucy‘,‘lily‘,‘mike‘]) print(names) print(names.__next__())#lucy print(names.__next__())#lily print(names.__next__())@mike print(names.__next__())#StopIteration
生成器generator
定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器
def cash_money(amount): while amount>0: amount-=100 yield 100#yield的主要效果呢,就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间还可以再重新调用这个函数,从上次yield的下一句开始执行。 print("又来取钱啦!") atm=cash_money(500) print(type(atm))#<class ‘generator‘> print(atm.__next__())#100 print(atm.__next__())#又来取钱啦!100 print(atm.__next__())#又来取钱啦!100 print(atm.__next__())#又来取钱啦!100 print(atm.__next__())#又来取钱啦!100
还可通过yield实现在单线程的情况下实现并发运算的效果:异步
import time def consumer(name): while True: print("%s准备吃包子啦!"%name) while True: baozi=yield print("包子[%s]来了,被%s吃了"%(baozi,name)) def producer(name): c=consumer(‘A‘) c2=consumer(‘B‘) c.__next__() c2.__next__() print("老子开始准备做包子啦") for i in range(10): time.sleep(1) print("做了2个包子!") c.send(i) c2.send(i) producer("alex")
装饰器
def login(func):#func=tv def inner(arg):#arg=‘lily‘ print("passed user verification...") return func(arg)#执行func(arg)=tv(‘lily‘) return inner#返回的inner,inner代表的是函数,非执行函数,其实就是将原来的tv(name)函数塞进另外一个函数中 def home(name): print("Welcome [%s] to home page"%name) @login#装饰器 def tv(name):#执行tv(‘lily‘) print("Welcome [%s] to tv page"%name) def moive(name): print("Welcome [%s] to moive page"%name) tv(‘lily‘)#tv的内存地址加()
上述代码的理解解析:
- 执行login函数,并将 @login下面的函数tv作为login函数的参数,即:@login 等价于login(tv)
所以,内部就会去执行:
def inner:
print("passed user verification...")
return func() # func是参数,此时 func 等于 tv
return inner # 返回的 inner,inner代表的是函数,非执行函数
其实就是将原来的 tv 函数塞进另外一个函数inner中
- 将执行完的 login 函数返回值赋值给@login下面的函数的函数名tv
login函数的返回值是inner:
def inner:
print("passed user verification...")
return func()#tv(),此处的 tv表示原来的tv函数
然后,将此返回值再重新赋值给tv,即:
新tv = def inner:
print("passed user verification...")
return 原来tv()
所以,以后业务部门想要执行tv函数时,就会执行 新tv函数,在 新tv函数内部先执行验证,再执行原来的tv函数,然后将原来tv函数的返回值返回给了业务调用者。如此一来, 即执行了验证的功能,又执行了原来tv函数的内容,并将原tv函数返回值返回给业务调用
递归
递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。
递归算法所体现的“重复”一般有三个要求:
一是每次调用在规模上都有所缩小(通常是减半);
二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。
def calc(n): print(n)#10 5 2.5 1.25 if n/2>1: res=calc(n/2)#calc(10/2) calc(5/2) calc(2.5/2) print(‘res:‘,res)#1.25 2.5 5等同于执行calc()print(n)print("N:",n)#1.25 2.5 5 10 return n #N:1.25->return n->calc(1.25)->res:1.25->n=1.25*2->N:2.5->return n->calc(2.5)->res:2.5->n=2.5*2->N:5->return n->calc(5)->res:5->n=5*2->N:10->return 10calc(10)
10
5.0
2.5
1.25
#1.25/2>1不成立,执行print("N:",n)
N: 1.25
res: 1.25
N: 2.5
res: 2.5
N: 5.0
res: 5.0
N: 10
通过递归实现斐波那契数列:def func(arg1,arg2,stop): if arg1==0: print(arg1,arg2) arg3=arg1+arg2 print(arg3) if arg3<stop: func(arg2,arg3,stop) func(0,1,20)
算法基础之二分查找
def binary_search(data_source,find_n):[1,4,7,10,13,16,19] mid=int(len(data_source)/2)#data_source中间元素对应的索引值3,data_source[mid]=data_source[3]=10 if len(data_source)>1: if data_source[mid]>find_n: print("data in left of [%s]"%data_source[mid]) binary_search(data_source[:mid],find_n)#data_source[:mid]:切分,把右边的切去,保留左边的 elif data_source[mid]<find_n: print("data in right of [%s]"%data_source[mid]) binary_search(data_source[mid:],find_n)#data_source[mid:]:切分,把左边的切去,保留右边的 else: print("found find_n",data_source[mid]) else: print("can‘t find it") data=list(range(1,20,3)) #print(data) binary_search(data,13)