闭包
:
f2.__closure__(判断是否为闭包,是返回地址,否返回None)
定义:内部函数引用了外部函数的变量(非全局)
def f1(b):
def f2():
print(b) # 这样也是闭包
闭包的常用状态:
def f1(b):
def f2():
print(b)
return f2
ff = f1('hhh')
ff() # 输出 hhh
装饰器
:
作用:在不改变函数的调用方式的情况下,给函数的前后添加新的功能
先来一个万能模板:
defwrapper(func):
definner(*args,**kwargs):
"""被装饰函数执行之前要添加的代码"""
ret = func(*args,**kwargs)
"""被装饰函数执行之后要添加的代码"""
return ret
return inner
①#从最简单的装饰器
deftimmer(qqx):#timmer是装饰器的名字,传入的参数就是被装饰的函数
definner():#在装饰器中需要定义一个内部函数
print('调用func之前')
qqx() #被装饰的函数,并且要执行
print('调用func之后')
returninner#将内部函数的名字返回
@timmer#语法糖 func = timmer(func)
deffunc():
print('公司好老板好同事好')
func()
②# 完整的装饰-万能的装饰
deftimmer(qqxing):#timmer是装饰器的名字,传入的参数就是被装饰的函数
definner(*args,**kwargs):#在装饰器中需要定义一个内部函数
print('调用func之前')
ret = qqxing(*args,**kwargs)#被装饰的函数,并且要执行
print('调用func之后')
return ret
return inner#将内部函数的名字返回
@timmer#语法糖 func = timmer(func)
deffunc(name):
print('%s的公司好老板好同事好'%(name))
return 1111111111
ret = func('哈哈')
print('result : %s'%ret)
### 调用func之前
### 俊杰的公司好老板好同事好
### 调用func之后
### result : 1111111111
③
#装饰器:开放封闭原则
用装饰器实现,访问art或者dar函数,登陆一次之后,无需再次登录
flag = False
deflogin(func):
definner(*args,**kwargs):
globalflag
ifflag ==False:
username = input('用户名:')
password = input('密码:')
if username =='alex'and password =='somebody':
print('登录成功')
flag = True
if flag ==True:
ret = func(*args,**kwargs)
return ret
return inner
@login
defart():
print('欢迎来到文章页')
@login
defdar():
print('欢迎来到日记页')
art()
dar()
④
deflog(func):
definner(*args,**kwargs):
f =open('geci','a',encoding='utf-8')
f.write('你要调用%s函数了\n'%func.__name__)
f.close()
ret = func(*args,**kwargs)
return ret
return inner
@log
deff1():
print('f1')
@log
deff2():
print('f2')
f1()
f2() ### 成功将'你要调用f1函数了你要调用f2函数了'写入’geci'文件
扩充:
r: 可读 文本操作模式
w: 可写 文本操作模式
rb: 直接操作二进制
wb: 直接操作二进制
当拿到的是纯文字,就用文本操作的模式
当你拿到的是字节,就用二进制操作模式
迭代器:
__iter__
内部含有__iter__方法的数据类型,就是可迭代的 ------可迭代协议
print(dir(l)) # 打印关于l的方法
迭代器
:iterator
1、一个容器,我们从这个容器当中一个接着一个把值取出来的过程就是迭代的过程。
2、用法:可迭代的 == 可迭代对象 Python一切皆对象
①
print(dir(l)) # 打印关于l的方法
print(dir(lst_iter))
print(set(dir(lst_iter)) - set(dir(l))) # 两个用法的差集
list_iter.__next__() # 迭代器比可迭代的多一个__next__方法
②
l = ['ha','hei','hou']
ret = l.__iter__()
print(ret.__next__()) # ha
print(ret.__next__()) # hei
print(ret.__next__()) # hou
3、
可迭代的必须 含有__iter__方法 # 可迭代协议
迭代器比可迭代的多一个__naxt__方法
迭代器:包含__naxt__,__iter__方法 # 迭代器协议
包含__naxt__方法的可迭代对象就是迭代器 ,迭代器是可迭代的一部分
4、如何判断一个变量是不是迭代器或者可迭代的
①
print('__iter__' in dir([1,2,3,4])) # True
print('__next__' in dir([1,2,3,4])) # False
②
from collections import Iterable # 可迭代
from collections import Iterator # 迭代器
print(isinstance([1,2,3,4],Iterable)) # True
str_iter = 'abc'.__iter__()
print(isinstance(str_iter,Iterator)) # True
print(isinstance('abc',Iterator)) # False
5、迭代器的特点:①惰性运算 ② 不可逆不可重复 ③ 节省内存
6、用while写for 循环:
l = [1,2,3,4,5]
l_iter = l.__iter__()
while True:
try:
print(l_ter.__next__())
except StopIteration:
break
7、目前我们已知的可迭代的都是Python提供给我们的:
range() f(文件) enumerate()
for 循环是让我们更简单的使用迭代器,用迭代器取值就不需要关心索引或者key的问题了。
生成器:
一、
生成器本身就是迭代器
生成器函数和普通函数之间的区别
生成器函数中含有 yield 关键字
生成器函数调用的时候不会立即执行,而是返回一个生成器。
二、
def g_func():
print('I am here.')
yield 1
print('I am OK!')
yield 2
g = g_func() # 若只到这一步,什么都不打印
print(g.__next__()) # 若没有 print ,只有g.__next__则只打印’ I am here.‘
### 结果:I am here. \n 1
print(g.__next__()) # 都打
三、
衣服问题:
def cloth():
for i in range(1,1000001):
yield '衣服%s'%i
g = cloth
for i in range(50): # 取出50件
print(g.__next__())
四、
send(和__next__一样,更高级的就是可以传值)
send 之前必须有一个__next__方法
def func():
print('*********')
a = yield 5
yield 10
g = func
num = g.__next__()
print(num)
num2 = g.send('jieshenziai')
print(num2)
从哪一个yield开始接着执行,就把一个值传给那个yield。
send 不能做第一个触发器,send前必须有一个yield。
②文件追踪(最后一行)需要保存底下下才显示:
def tail():
f = open('文件',encoding='utf-8')
f.seek(0,2) (光标移动到最后)
while True:
line = f.readline()
if line:
yield line
import time
time.sleep(0,1)
g = tail()
for i in g:
print(i.strip())
num2 = g.send('惹人感慨')
③下面是一个比较6的 计算移动平均值。
def average():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total / count
g_avg = average()
g_avg.__next__()
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(50))
五、生成器的预激装饰器
def init(func):
def inner(*args,**kwargs):
ret = func(*args,**kwargs)
ret.__next__()
return ret
return inner
因为,send之前总是要 next 所以,就有了这个预激装饰器
六、小栗子输出 A,B,C,D
①方法
def func():
a = 'AB'
b = 'CD'
for i in a:
yield i
for i in b:
yield i
func()
g = func()
for i in g:
print(i)
②方法
def func():
a = 'AB'
b = 'CD'
yield from a # 这是py3 中特有的
yield from b
func()
g = func()
for i in g:
print(i)
七、触发执行的方式:
next(send):执行几次那几个数据,取完会报错
for循环:每次取一个,取完为止,不会报错
八、生成器表达式
列表推导式:
y = range(30)
x = [i*i for i in y ]
生成器表达式:(这个比较好,因为它每次就取一个)
g = (i*i for i in y )
for i in g:
print(i)
小栗子:(鸡蛋和鸡的关系)
l = ['鸡蛋%s'%i for i in range(10)]
print(l)
laomuji = ('鸡蛋%s'%i for i in range(10))
for egg in laomuji:
print(egg)
小结:
惰性运算:不取值就不计算,且每一个值只能被取一次,取完为止
可迭代对象:
拥有__iter__方法
特点:惰性运算
例如:range(),str,list,tuple,dict,set
迭代器:
拥有__iter__和__next__方法
例:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),
reversed(list_o),map(func,list_o),filter(func,list_o),file_o
生成器Generator:
本质:迭代器,所以拥有__iter__和__next__方法
特点:惰性运算,开发者自定义
使用生成器的优点:
1、延迟计算,一次返回一个结果。不会一次生成所有结果,对大数据量处理,非常有用。
2、提高代码可读性