目录
1 闭包函数
闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。
闭包函数:传参的另外一种方式,参数+函数包在一起传出去
1.1 函数传参方式
# 函数传参的方式一:使用参数
def inner(x):
print(x)
inner(1)
inner(1)
inner(1)
# 函数的传参方式二:闭包函数,把变量和函数一起包起来,下次要用直接调用
def outter(x):
def inner():
print(x)
return inner
inner = outter(2) # inner # f = inner
inner()
inner()
inner()
1.2 闭包函数的应用
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
import requests
def get_res(url):
res = requests.get(url)
print(res.txt)
get_res('https://www.baidu.com/')
get_res('https://www.baidu.com/')
get_res('https://www.baidu.com/')
get_res('https://www.taobao.com')
get_res('https://www.taobao.com')
get_res('https://www.taobao.com')
get_res('https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-links-3.20.5af911d9iW0QkW')
get_res('https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-links-3.20.5af911d9iW0QkW')
get_res('https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-links-3.20.5af911d9iW0QkW')
上面的方式极其复杂,我们如果使用默认参数也只能解决一个网址,因此我们可以考虑使用闭包的方式。
import requests
def func(url):
def get_res():
res = requests.get(url)
print(res.text)
return get_res
baidu_spider = func('https://www.baidu.com/')
baidu_spider()
baidu_spider()
taobao_spider = func('https://www.taobao.com')
taobao_spider()
taobao_spider()
2 装饰器
2.1 装饰器的定义
装饰器:装饰的工具(函数),这个函数有装饰的作用
装饰器本质就是一个函数A,装饰的对象也是一个函数B,用一个函数A去装饰一个函数B
装饰器的实现必须遵循两大原则:
1.不改变函数B的调用方式
2.不改变函数B的源代码
def A():
"""装饰器"""
pass
def B():
"""被装饰的对象"""
pass
B()
2.2 装饰器的使用
def index():
"""被装饰的函数"""
print('hello,index')
index()
# 打印函数运行的时间
# 1.改变函数体代码,没改变调用方式
import time
def index():
start = time.time()
print('hello,index')
time.sleep(1)
end = time.time()
print(end - start)
index()
# 2没改变调用方式,也没改变源码,但是不通用
import time
def index():
"""被装饰的函数"""
print('hello,index')
def index1():
print('hello,index')
start = time.time()
index1()
time.sleep(1)
end = time.time()
print(end - start)
# 装饰器
# 检测index的运行的时间,但是不能改变index的调用方式,以及index的源码
import time
def deco(func): # func = index
"""装饰器函数"""
def inner():
start = time.time()
func() # index
time.sleep(1)
end = time.time()
print(end - start)
return inner
def index():
"""被装饰的函数"""
print('hello,index')
def index1():
print('hello,index1')
index = deco(index) # index = inner
index()
2.3 装饰器语法糖
在被装饰函数正上方,并且是单独一行写上@装饰器名
import time
def deco(func):
def f1(*args,**kwargs):
print('args:',args) # (10,)
print('kwargs:',kwargs)
start = time.time()
# *args = *(10,)10
res = func(*args,**kwargs) # 真正的index()
end = time.time()
print(end - start)
return res
return f1
@deco # 语法糖(更精简的代码) index = deco(index)
def index(x,a=1):
print('x',x)
print('a',a)
print('hello index')
time.sleep(1)
return 123
# 重新创建的index = deco(index真正的index)
index = deco(index) # index = f1
res = index(10) # f1(1)
3 三层装饰器
三层装饰器:给双层装饰器加参数
# 判断账号密码来自于哪个地方
def auth(engine):
def login(func):
def inner(*args, **kwargs):
# 登录功能
if engine == 'file':
username = input('username:')
pwd = input('pwd:')
if username == 'nick' and pwd == '123':
print('登录成功')
res = func(*args, **kwargs) # shopping()
return res
else:
print('登录失败')
elif engine == 'db':
print('账号密码来自于数据库,非法请求')
return inner
return login
@auth('db')
def shopping():
print('shopping')
# login = auth('db') # login = login
# shopping = login(shopping) # shopping = inner
shopping() # inner()
4 装饰器模板
4.1 双层装饰器
def outter(func):
def wrapper(*args,**kwargs): # wrapper 是未来要运行的函数
# 加功能
res = func(*args,**kwargs) # func是被装饰的函数
return res
return wrapper
@outter
def shopping():
print('shopping')
4.2 三层装饰器
def sanceng(engine):
def outter(func):
def wrapper(*args, **kwargs): # wrapper 是未来要运行的函数
# 加功能
print(engine)
res = func(*args, **kwargs) # func是被装饰的函数
return res
return wrapper
return outter
@sanceng('file')
def shopping():
print('shopping')
4.3 叠加装饰器
def outter1(func): # func = wrapper2
def wrapper1(*args,**kwargs): # wrapper 是未来要运行的函数
print('---------')
res = func(*args,**kwargs) # func是被装饰的函数 # wrapper2
print('---------')
return res
return wrapper1
def outter2(func): # func = index
def wrapper2(*args,**kwargs): # wrapper 是未来要运行的函数
print('1111111111')
res = func(*args,**kwargs) # func是被装饰的函数 # index()
print('1111111111')
return res
return wrapper2
# @outter1 # index = outter1(index)
# @outter2 # index = outter2(index) # 先运行最下面的装饰器
# # index
def index():
print('index')
# index重新定义的index = outter2(index 真正的index)
index = outter2(index) # index = wrapper2
# index再一次重新定义的index = outter1(index重新定义的index,即wrapper2)
index = outter1(index) # index = wrapper1
index() # wrapper1()
'''
---------
1111111111
index
1111111111
---------
'''
5 迭代器
5.1 可迭代对象
具有__iter__
方法的对象就是可迭代对象
x = 1 # 不可迭代对象
s = 'nick' # 可迭代对象
s.__iter__()
lt = [1,2,3] # 可迭代对象
dic = {'a':1,'b':2} # 可迭代对象
tup = (1,) # 元组只有一个元素必须得加逗号 # 可迭代对象
se = {1,2,3} # 可迭代对象
f = open('test.py') # 可迭代对象
def func(): # 不可迭代对象
pass
# 有__iter__()方法的对象就是可迭代对象,然后除了数字类型和函数之外都是可迭代对象
s = 'nick'
s_iter = s.__iter__()
print(s_iter.__next__()) # 基于索引(基于上一次结果)通过__next__进行迭代
print(s_iter.__next__())
print(s_iter.__next__())
print(s_iter.__next__())
dic = {'a':1,'b':2} # 可迭代对象
dic['a']
dic_iter = dic.__iter__() # 不依赖索引取值 # 迭代器对象
print(dic_iter.__next__()) # a
print(dic_iter.__next__()) # b
# print(dic_iter.__next__()) # 报错
5.2 迭代器对象
具有__iter__
以及__next__
方法的叫做迭代器对象
缺点:
- 取值麻烦,只能一个一个取,并且只能往后取,值取了就没了
- 无法使用len()方法获取长度
s = 'nick' # 可迭代对象,不属于迭代器对象
s.__iter__()
lt = [1,2,3] # 可迭代对象,不属于迭代器对象
dic = {'a':1,'b':2} # 可迭代对象,不属于迭代器对象
tup = (1,) # 元组只有一个元素必须得加逗号 # 可迭代对象,不属于迭代器对象
se = {1,2,3} # 可迭代对象,不属于迭代器对象
f = open('test.py') # 可迭代对象,迭代器对象
# 只有文件是迭代器对象
5.3 for循环原理
for循环称为迭代器循环,in后必须是可迭代的对象。
lt = [1,2,3]
lt_iter = lt.__iter__()
while 1:
try:
print(lt_iter.__next__())
except StopIteration:
break
for i in lt: # 可迭代对象;迭代器对象 # 不依赖索引取值,而是迭代取值
print(i)
# 1,首先使用iter把lt变成迭代器对象;对于文件也要使用iter方法把文件再一次iter下
# 2. 然后使用next方法进行迭代取值
# 3. 判断StopIteration异常,遇到异常终止
dic ={'a':1,'b':2}
for i in dic:
print(i)
# 1. 把lt(可迭代对象/迭代器对象)用__iter__方法转换成迭代器对象
# 2. 使用__next__取出迭代器里的所有值
# 3. 使用__next__方法取尽迭代器中的所有值,一定会报错,通过异常捕捉退出while循环
# 解决了不依赖索引取值
f = open('time.py') # 可迭代对象,迭代器对象
f_iter = f.__iter__()
print(id(f_iter))
f_iter_iter = f_iter.__iter__()
print(id(f_iter_iter)) # 两次打印的id值是一样的
dic ={'a':1,'b':2}
dic_iter = iter(dic)
print(next(dic_iter))
print(next(dic_iter)) # 相当于内置方法