一、迭代器
1、迭代器:拥有__iter__和__next__方法的对象就是迭代器。
2、迭代:是访问集合元素的一种方式,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫迭代。
3、可迭代协议:内部实现了__iter__方法。
4、迭代器协议:必须拥有__iter__方法和__next__方法。
5、能被for循环的内容:list,dic,str,set,tuple,f.open(),range(),enumerate
6、dir()方法能获取对应数据类型的所有方法。例如:print(dir([]))
①利用dir()查看共有方法。
a = set(dir([])) & set(dir({})) & set(dir("")) & set(dir(range(1)))
print(a) #{'__gt__', '__iter__', '__ge__', '__delattr__', '__new__', '__contains__', '__le__', '__str__', '__init_subclass__', '__init__', '__class__', '__setattr__', '__eq__', '__sizeof__', '__getitem__', '__getattribute__', '__lt__', '__hash__', '__subclasshook__', '__dir__', '__reduce__', '__format__', '__repr__', '__ne__', '__doc__', '__len__', '__reduce_ex__'}
②判断int类型是否有__iter__方法。
print("__iter__" in dir(int)) #False
7、iter()方法的作用:返回一个迭代器。
a = [1,2,3,4,5]
b = a.__iter__()
print(b) #<list_iterator object at 0x00000000020E7470>处理list对象的迭代器位于XX地址
print(next(b)) #1,运行一次迭代器,输出1
8、打印迭代器中的方法:
a = set(dir([].__iter__())) - set(dir([])) #求差值
print(a) #{'__length_hint__', '__setstate__', '__next__'}
9、for循环原理
①for循环一个可迭代对象(实现__iter__方法)
②__iter__方法返回一个迭代器(迭代器实现了__iter__和__next__方法)
③for先判断对象哪些范围需要迭代,然后调用迭代器的__next__方法获取值
10、迭代器作用:节约内存
11、数据类型转换:例如元组和列表间的转换底层,就是使用迭代器实现的
a = "hello"
b = list(a)
print(b) #['h', 'e', 'l', 'l', 'o']
c = (1,2,3)
d = list(c)
print(d) #[1, 2, 3]
12、利用迭代器,生成斐波那契数列
class Fib():
def __init__(self,num):
self.num = num
self.a = 1
self.b = 1
self.current = 1
def __iter__(self):
return self #返回自己,调用自己的__next__方法
def __next__(self):
if self.current <= self.num:
a = self.a
self.a,self.b = self.b,self.a + self.b
self.current += 1
return a
else:
raise StopIteration
for i in Fib(10):
print(i,end = " ") #1 1 2 3 5 8 13 21 34 55 89
二、生成器
1、生成器:本质就是迭代器。生成器包括两种,生成器函数和生成器表达式。
2、生成器函数:一个包含yield关键字的函数,就是生成器函数。并且,yield不能和return公用,yeild只能在函数内使用。
①生成器函数执行后,会得到一个生成器作为返回值,并不会执行函数体。
②执行了__next__方法后,才会执行函数体,并获得返回值。
③next()内置方法,内部调用生成器函数的__next__方法
④yield和ruturn相同的是,都可以返回值,但是不同的是,yield不会结束函数
3、创建一个生成器函数,执行,得到一个生成器,并调用
def func(): #创建生成器函数
for i in range(5):
yield i #包含yield,是生成器函数
a = func() #执行生成器函数,得到一个生成器
print(next(a)) #0 执行生成器,得到返回值
print(next(a)) #1
print(next(a)) #2
4、创建一个生成器生成器,定义多个yield值
def func(): #创建生成器函数
yield 1
yield 3
yield 2
a = func() #调用生成器函数,得到生成器
print(next(a)) #1
print(next(a)) #3
print(next(a)) #2
5、创建生成器,生成5桶康师傅方便面
def ksf():
for i in range(1,6):
yield "生产第%d桶康师傅方便面"%i
a = ksf()
for i in a:
print(i,end = " ") #生产第1桶康师傅方便面 生产第2桶康师傅方便面 生产第3桶康师傅方便面 生产第4桶康师傅方便面 生产第5桶康师傅方便面
6、sent():在获取下一个值的时候,给上一个yield的位置传递一个数据
①第一次使用生成器的时候,是用next获取第一个值
②最后一个yield不能接受外部的值
7、使用sent()方法给yield传递参数
def func():
a = 0
b = yield a
print("----------",b)
yield 9
yield 3
a = func()
print(next(a)) #移到下一个yield并打印出来
b = a.send("123") #给上一个yield的位置传递参数,并获得下一个yield值,赋值给b
print(b)
print(next(a)) #移到下一个yield并打印出来
8、利用生成器,和sent()方法,计算移动平均值
def avrage1():
count = 1
get_num = 0
avg = 0
sum = 0
while True:
get_num = yield avg
sum += get_num
avg = sum / count
count += 1
a = avrage1()
next(a) #到达第一个yield的位置
print(a.send(10)) #10.0
print(a.send(20)) #15.0
print(a.send(30)) #20.0
9、利用yield from遍历出可变数据类型中的数据
def func():
yield from "abc" #遍历字符串的所有元素
yield from range(3) #遍历数字范围内的所有数字
a = func() #调用函数
b = list(a) #将函数转化为列表类型
print(b) #['a', 'b', 'c', 0, 1, 2]
10、生成器表达式:
a = (i for i in range(5)) #创造一个生成器表达式
print(a) #返回一个生成器
b = [i for i in range(5)] #列表推导式
print(b)
11、利用生成器表达式,模拟老母鸡下蛋
a = ("鸡蛋%d"%i for i in range(1,10)) #生成器表达式
print(list(a))
12、生成器作用:可以实现多任务。
三、装饰器
1、装饰器:本质是一个闭包函数。
2、作用:在不修改原函数及其调用方式的情况下,对原函数功能进行扩展
3、闭包函数
①闭包函数必须有内嵌函数
②内嵌函数必须引用外层函数的变量
③闭包函数必须返回内嵌函数的函数名
4、创建一个闭包函数
5、判断是否闭包函数的方法__closure__,如果是,输出含有cell的数据,如果不是,返回None
def outer(tax):
def inner(a):
c = a * tax #调用外层函数的变量
return c
print(inner.__closure__) #判断是否是闭包函数
return inner #返回内嵌函数的函数名
a = outer(0.1) #调用闭包函数,传递外层参数
b = a(100) #调用内嵌函数,传递参数
print(b) #打印返回值
6、语法糖@
格式:@装饰器名称
7、创建一个计算函数执行花费时间的闭包函数
import time
def timer(x): #装饰器
def inner():
start = time.time()
x()
end = time.time()
print(end - start)
return inner
@timer #语法糖,相当于func = timer(func)
def func():
sum = 0
for i in range(10000000):
sum += i
print(sum)
func()
8、创建一个带返回值的装饰器
import time
def timer(func):
def inner():
start = time.time()
a = func() #接受返回值
end = time.time()
print(end - start)
return a #返回返回值
return inner
@timer
def fun():
print("abc")
return "ok..." #设置返回值
a = fun()
print(a)
9、创建一个可以传递任意参数的装饰器
def decor(x): #创建装饰器
def inner(*args,**kwargs):
print("**********") #打印格式
x(*args,**kwargs)
print("**********") #打印格式
return inner
@decor
def vocal_concert(*args,**kwargs):
print(args)
for i in args:
print(i,end = " ")
print()
for k,v in kwargs.items():
print(k,v)
print("演唱会")
vocal_concert("刘德华","张惠妹",age = 30,address = "广州")
10、创建带返回值的可以传递任意参数的装饰器
def decor(x):
def inner(name,date,address):
print("**************************************")
y = x(name,date,address)
print("**************************************")
return y
return inner
@decor
def func(name,date,address):
print("{},{},{},地表最强演唱会".format(name,date,address))
return "不见不散"
a = func("周杰伦","2019-5-8","广州")
11、使用@wraps(func)解决被装饰函数的信息不能查看的问题
from functools import wraps #导入wraps方法
def decor(x):
@wraps(x) #解决不能查看注释的bug
def inner(name,date,address):
print("**************************************")
y = x(name,date,address)
print("**************************************")
return y
return inner
@decor
def func(name,date,address):
"""
:param name:
:param date:
:param address:
:return:
"""
print("{},{},{},地表最强演唱会".format(name,date,address))
return "不见不散"
a = func("周杰伦","2019-5-8","广州")
print(func.__doc__) #显示参数
print(func.__name__) #显示函数名
12、给函数添加多个装饰器
def decor1(func):
def inner():
print("11111")
func()
print("22222")
return inner
def decor2(func):
def inner():
print("33333")
func()
print("44444")
return inner
@decor1
@decor2
def hello():
print("hello")
hello()
13、@property装饰器:把一个方法调用方式变成属性调用方式。将一个方法当成属性使用。
①只能在面向对象中使用。
②可以直接调用被装饰的函数的函数名
③只能装饰不带参数的方法
14、@property装饰器私有方法的getter和setter方法。
class Stu():
def __init__(self,name,age):
self.name = name
self.__age = age
@property #getter方法
def message(self):
print("运行getter")
return self.__age
@message.setter #setter方法
def message(self,x):
print("运行到setter")
self.__age = x
a = Stu("张三",19)
a.message = 28
print(a.message)
15、使用@property装饰器,求圆形的周长和面积
from math import pi
class Circle():
def __init__(self,r):
self.r = r
@property
def perimeter(self):
return 2 * pi *self.r
@property
def area(self):
return pi * self.r * self.r
a = Circle(10)
print(a.perimeter) #62.83185307179586
print(a.area) #314.1592653589793
16、使用@property装饰器,BMI指数
class People():
def __init__(self,name,sex,weight,height):
self.name = name
self.sex = sex
self.weight = weight
self.height = height
@property
def BMI(self):
return self.weight / (self.height ** 2)
a = People("张三","男",70,1.85)
print(a.BMI) #20.45288531775018
四、类的各种方法
1、对象方法
2、静态方法
class A():
count = 0
def __init__(self,name):
self.name = name
A.count += 1
def duixiangfangfa(self):
print("对象方法")
@staticmethod
def jingtai():
print("静态方法")
@classmethod
def leifangfa(cls):
print("类方法,调用类属性 count = ",cls.count)
a = A("李白")
a.duixiangfangfa()
A.jingtai()
a.jingtai()
A.leifangfa()
3、类方法
class Goods():
__discount = 1 #类属性
def __init__(self,name,price):
self.name = name #对象属性
self.__price = price #对象属性
@classmethod #类方法
def change_discount(cls,new_discount):
cls.__discount = new_discount
@property
def price(self):
return self.__price * self.__discount
a = Goods("苹果",10)
print(a.price)
Goods.change_discount(0.8) #调用类方法
print(a.price)
b = Goods("香蕉",10)
print(b.price)
作业
1、迭代器练习,找质数
class PrimeNumbers:
def __init__(self, start, end): #初始化对象属性
self.start = start
self.end = end
def isPrimeNum(self, k): #如果是质数,返回True
if k < 2:
return False
for i in range(2, k):
if k % i == 0:
return False
return True
def __iter__(self): #生成迭代器
for k in range(self.start, self.end + 1):
if self.isPrimeNum(k):
yield k
for x in PrimeNumbers(1, 100):
print(x)
2、生成器练习
def read_file(fpath):
BLOCK_SIZE = 6
with open(fpath, 'r') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return
import os
g = read_file(os.getcwd() + '\\aa.txt')
for content in g:
print(content)