一、迭代器
(一)什么是迭代器
迭代是访问集合元素的一种方式。拥有__iter__方法和__next__方法的对象就是迭代器。
只要含有__iter__()的都是可迭代的。
# 查看共有方法
print(set(dir([]))&set(dir(''))&set(dir({}))&set(dir(range(2))))
说明int类型不可迭代:
print('__iter__'in dir(int)) # False
a=set(dir([].__iter__()))
b=set(dir([]))
print(a-b) # {'__next__', '__setstate__', '__length_hint__'}
# __length_hint__--获取元素的个数
# __setstate__--决定取值的位置
# __next__--获取元素
__iter__()作用:返回一个迭代器。
__iter__()中有一个__next__()方法,这个方法可以迭代。
k=[1,2,3]
d=k.__iter__()
print(d.__next__())
print(d.__next__())
print(d.__next__())
(二)for循环原理
1.for循环一个可迭代的对象(实现__iter__()方法)。
2.__iter__()方法返回一个迭代器(迭代器实现了__init__()和__next__())。
3.for先判断对象是否可迭代,然后调用迭代器的__next__()方法获取值。
(三)迭代器作用
节约内存,取的时候再生成数据。
(四)应用场景
1.数据类型转换
str1='hello'
lst1=list(str1)
print(lst1)
tuple1=('a','b','c')
lst2=list(tuple1)
print(lst2)
2.斐波那契序列
class Fib():
def __init__(self,num):
self.num=num
self.a=1
self.b=1
self.current=1
def __iter__(self):
return self
def __next__(self):
if self.current<=self.num:
print(self.a)
self.a,self.b=self.b,self.a+self.b
self.current+=1
else:
raise StopIteration
for x in Fib(10):
pass
二、生成器
生成器的本质就是迭代器。
生成器包括两种:生成器函数和生成器表达式。
(一)生成器函数
一个包含yield关键字的函数就是一个生成器函数。
yield和return不能共用,且yield只能存在于函数中。
1.生成器函数执行之后会得到一个生成器作为返回值,并不会执行函数体。
2.执行了__next__()方法之后才会执行函数体,并且获得返回值。
3.next()内置函数,内部调用生成函数的__next__()方法。
4.yield和return相同的是可以返回值,但是不同的是yield不会结束函数。
def shengchan(n):
i=1
while i<=n:
yield i
i+=1
x=shengchan(5)
print(x)
# for y in x:
# print(y)
print(x.__next__())
print(x.__next__())
print(next(x))
print(next(x))
print(x.__next__())
def dee():
yield 1
yield 2
yield 3
x=dee()
print(x.__next__())
print(next(x))
print(next(x))
应用
斐波那契数列:
def fib(n):
a,b=1,1
i=1
while i<=n:
yield a
a,b=b,a+b
i+=1
for x in fib(10):
print(x)
(二)send()
使用send()的注意事项:
1.第一次使用生成器的时候,是用next获取下一个值。
2.最后一个yield不能接手外部的值。
def g():
print('a')
x = yield 10
print('接收到数据', x)
yield x + 5 # 最后一个yield不能赋值
x = g()
print(next(x)) # 第一次使用生成器要用next()
b = x.send(999)
print(b)
应用:
计算平均值,送几个,算几个:
def g():
count=1
get_num=0
avg=0
total=0
while True:
get_num=yield avg
total=total+get_num
avg=total/count
count+=1
x=g()
next(x)
print(x.send(10))
print(x.send(20))
print(x.send(30))
(三)yield from
# 使用for循环取出生成器中所有的值
def gen1():
for c in 'AB':
yield c
for i in range(3):
yield i
for x in gen1():
print(x)
# 使用yield from
def g():
yield from 'AB'
yield from range(5)
for x in g():
print(x)
(四)生成器表达式
b=(i for i in range(5))
print(b)
for x in b:
print(x)
a=('鸡蛋%d个'%(i+1) for i in range(10))
print(a)
# next记录了当前的状态
print(next(a))
print(a.__next__())
print(list(a)) # 从第三个开始
三、装饰器
(一)闭包
要求:
1.闭包函数必须有内嵌函数
2.内嵌函数必须要引用外层函数的变量
3.闭包函数返回内嵌函数的地址(函数名称)
重点!!闭包会保留资源,不释放。
def out(b):
a=3
def inside(x):
return a*x+b
return inside
func=out(3)
print(func(3))
判断闭包函数的方法__closure__
def out(b):
a=3
def inside(x):
return a*x+b
print(inside.__closure__) # 有cell元素,是闭包
return inside
func=out(3)
print(func(3))
def out():
b=9
def inner():
print('haha')
print(inner.__closure__) # None--不是闭包
return inner
x=out()
x()
这里有一个之前说过的问题,在了解了闭包后会更加好理解。
def func():
x=4
lst=[]
for i in range(3):
action=lambda x,i=i:x**i
lst.append(action)
return lst
b=func()
print(b[0](2)) # 1
print(b[1](2)) # 2
print(b[2](2)) # 4
b=[lambda x,i=i:x**i for i in range(3)]
print(b[0](2)) # 1
print(b[1](2)) # 2
print(b[2](2)) # 4
(二)装饰器
装饰器的本质:一个闭包函数。
作用:在不修改原函数及其调用方式的情况下对原函数功能进行拓展。
import time
def decor(f):
def inner():
t=time.time()
f()
t2=time.time()
print('运行时间:{}'.format(t2-t))
return inner
@decor
def func():
s=0
for i in range(1000000):
s+=1
print(s)
func()
添加多个装饰器:
def decor(f):
def inner():
print('****')
f()
print('****')
return inner
def decor2(f):
def inner():
print('####')
f()
print('####')
return inner
@decor
@decor2
def f1():
print('欢迎')
@decor
def f2():
print('走好')
f1()
print()
f2()
创建带参数和返回值的装饰器:
from functools import wraps
def decor(f):
@wraps(f) # 解决被装饰函数不能查看信息的bug
def inner(a,b):
print('*******')
d=f(a,b)
print('*******')
return d
return inner
@decor
def func(a,b):
'''
:param a:
:param b:
:return:
'''
c=a+b
return c
print(func(2,3))
print(func.__doc__)
(三)@property装饰器
把一个方法的调用方式变为属性调用方式(将一个方法当成一个属性使用)。
只能在面向对象中使用。
只能修饰不带参数的方法。
class A():
def __init__(self,name):
self.name=name
@property # 把方法作为属性使用
def age(self):
return self.__age # 属性不能与函数名重名
@age.setter
def age(self,age):
if age<0 or age>100:
print('错误')
self.__age=-1
else:
self.__age=age
a=A('张三')
a.age=39
print(a.age)
a.age=400
print(a.age)
class A():
def __init__(self,name):
self.__name=name
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name=name
a=A('张三')
print(a.name)
a.name='李四'
print(a.name)
求圆的面积和周长
from math import pi
class Circle():
def __init__(self,r):
self._r=r
@property
def c(self):
return 2*pi*self._r
@property
def area(self):
return pi*self._r*self._r
y=Circle(1)
print(y.c)
print(y.area)
BMI指数计算
class Person():
def __init__(self,name,w,h):
self.name=name
self.weight=w
self.height=h
@property
def bmi(self):
return self.weight/(self.height**2)
p=Person('吕佳',48,1.63)
print(p.bmi)