闭包函数

一、什么是闭包?

闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。

def outter():
x = 1 def inner():
print(x)
return inner f = outter() def f2():
x = 2
f() f2() # 1
1.1 两种为函数传参的方式

为函数传参的方式一:使用参数的形式

def func(x):
print(x) func(1)
func(1)
func(1) # 1
# 1
# 1

为函数传参的方式二:包给函数

def outter(x):
x = 1 def inner():
print(x)
return inner f = outter(1)
f()
f()
f()
# 查看闭包的元素
print(F"f.__closure__[0].cell_contents: {f.__closure__[0].cell_contents}") # 1
# 1
# 1
# f.__closure__[0].cell_contents: 1

举个栗子

def f2(x):
def f1():
print(x)
return f1 f1_1 = f2(1) #返回f1 + 1
f1_1() #调用f1,传参x = 1 # 1

二、闭包函数的应用

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

应用一(复杂):

import requests

def get(url):
res = requests.get(url)
print(res) get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng') #https://www.baidu.com
#https://www.baidu.com
#https://www.baidu.com
#https://www.cnblogs.com/linhaifeng
#https://www.cnblogs.com/linhaifeng
#https://www.cnblogs.com/linhaifeng

应用二(闭包):

#爬取
import requests def func(url):
def get():
res = requests.get(url)
print(res.text)
return get baidu_spider = func('http://www.iqiyi.com/')
baidu_spider()

无参装饰器

装饰器指的是为被装饰器对象添加额外功能,就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。

一、装饰器使用原则

装饰器的实现必须遵循两大原则:

  1. 不修改被装饰对象的源代码
  2. 不修改被装饰对象的调用方式

二、怎么用装饰器?

改变源代码(index内部代码块被改变):

import time

def index():
start = time.time()
print('welcome to index')
time.sleep(1)
end = time.time()
print(F"index run time is {start-end}") index() #welcome to index
#index run time is -1.0008180141448975

编写重复代码(index( )和f2( )都调用,而且time代码重复):

import time

def index():
print('welcome to index')
time.sleep(1) def f2():
print('welcome to index')
time.sleep(1) start = time.time()
index()
end = time.time()
print(F"index run time is {start-end}") start = time.time()
f2()
end = time.time()
print(F"f2 run time is {start-end}") #welcome to index
#index run time is -1.0046868324279785
#welcome to index
#f2 run time is -1.000690221786499

三、两种传参方式

第一种传参方式:改变调用方式

import time

def index():
print('welcome to index')
time.sleep(1) def time_count(func):
start = time.time()
func() #func()=index(),打印'welcome to index'
end = time.time()
print(f"{func} time is {start-end}") #打印 time_count(index) #运行time_count(),同时传参给func #welcome to index
#<function index at 0x102977378> time is -1.000748872756958

第二种传参方式:包给函数-外包

import time

def index():
print('welcome to index')
time.sleep(1) def time_count(func):
# func = 最原始的index
def wrapper():
start = time.time()
func()
end = time.time()
print(f"{func} time is {start-end}")
return wrapper # f = time_count(index)
# f() index = time_count(index) # index被重新定义,原来的index被覆盖,即index = wrapper,func = index
index() # wrapper() #依旧是以index()方式调用 #welcome to index
#<function index at 0x102977730> time is -1.0038220882415771

四、完善装饰器

上述的装饰器,最后调用index()的时候,其实是在调用wrapper(),因此如果原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。

import time

def index():
print('welcome to index')
time.sleep(1) return 123 def time_count(func):
# func = 最原始的index
def wrapper():
start = time.time()
res = func()
end = time.time()
print(f"{func} time is {start-end}") return res
return wrapper index = time_count(index) #index = wapper, func = index
res = index() #wapper(index)
print(f"res: {res}") #welcome to index
#<function index at 0x102977620> time is -1.0050289630889893
#res: 123

如果原始的index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper()=index(),所以给wrapper()方法传参即可。

import time

def index():
print('welcome to index')
time.sleep(1) return 123 def home(name):
print(f"welcome {name} to home page")
time.sleep(1) return name def time_count(func):
# func = 最原始的index
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f"{func} time is {start-end}") return res
return wrapper home = time_count(home) #func = home, home = wrapper
res = home('egon') #wrapper('egon') = fun('egon') = home('egon') = 'welcome egon to home page' = 'egon'
print(f"res: {res}") # res = func('egon') = home('egon') = 'egon' #welcome egon to home page
#<function home at 0x102977378> time is -1.0039079189300537
#res: egon

五、装饰器语法糖

在被装饰函数正上方,并且是单独一行写上@装饰器名

import time

def time_count(func):
# func = 最原始的index
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f"{func} time is {start-end}") return res
return wrapper @time_count # home = time_count(home)
def home(name):
print(f"welcome {name} to home page")
time.sleep(1) return name @time_count # index = time_count(index)
def index():
print('welcome to index')
time.sleep(1) return 123 res = home('egon') #func = home name = 'egon' --> welcome egon to home page --> print(f"{func} time is {start-end}")
print(f"res: {res}") # egon #welcome egon to home page
#<function home at 0x102977620> time is -1.0005171298980713
#res: egon

六、装饰器模板(重要)

def deco(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper

有参装饰器

无参装饰器套了两层有参装饰器套了三层

import time

current_user = {'username': None}

def login(func):
# func = 最原始的index
def wrapper(*args, **kwargs):
if current_user['username']:
res = func(*args, **kwargs) return res user = input('username: ').strip()
pwd = input('password: ').strip() if user == 'nick' and pwd == '123':
print('login successful')
current_uesr['usre'] = user
res = func(*args, **kwargs) return res
else:
print('user or password error') return wrapper @login #home = login(home)
def home(name):
print(f"welcome {name} to home page")
time.sleep(1) return name @login #index = login(index)
def index():
print('welcome to index')
time.sleep(1) return 123 res = index() #运行index之前运行糖果 wrapper(index) 继续运行 返回res = func 继续运行 即真正的index() #username: nick
#password: 123
#login successful
#welcome to index

对于上面的登录注册,我们把用户登录成功的信息写入内存当中。但是在工业上,用户信息可以存在文本中、mysql中、mongodb当中,但是我们只让用户信息来自于file的用户可以认证。因此我们可以改写上述的装饰器。

import time

current_user = {'username': None}

def login(func):
# func = 最原始的index
def wrapper(*args, **kwargs): if current_user['username']:
res = func(*args, **kwargs) return res user = input('username: ').strip()
pwd = input('password: ').strip() engine = 'file' if engine == 'file':
print('base of file')
if user == 'nick' and pwd == '123':
print('login successful')
current_uesr['usre'] = user
res = func(*args, **kwargs) return res
else:
print('user or password error')
elif engine == 'mysql':
print('base of mysql')
elif engine == 'mongodb':
print('base of mongodb')
else:
print('default') return wrapper @login
def home(name):
print(f"welcome {name} to home page")
time.sleep(1) @login
def index():
print('welcome to index')
time.sleep(1) res = index() #username: nick
#password: 123
#base of file
#login successful
#welcome to index

一、三层闭包

def f1(y):

    def f2():
x = 1 def f3():
print(f"x: {x}")
print(f"y: {y}")
return f3
return f2 f2 = f1(2) #f2(y = 2)
f3 = f2() #x = 1
f3() #到外部找x, y #倒着运行--->先找x, y--->找到x = 1--->y = 2--->结果输出 #x: 1
#y: 2

现在需求改了,我们需要判断用户动态的获取用户密码的方式,如果是file类型的,我们则让用户进行认证。因此我们可以使用有参装饰器。

import time

current_uesr = {'username': None}

def auth(engine='file'):

    def login(func):
# func = 最原始的index
def wrapper(*args, **kwargs): if current_user['username']:
res = func(*args, **kwargs) return res user = input('username: ').strip()
pwd = input('password: ').strip() if engine == 'file':
print('base of file')
if user == 'nick' and pwd == '123':
print('login successful')
current_uesr['usre'] = user
res = func(*args, **kwargs) return res
else:
print('user or password error')
elif engine == 'mysql':
print('base of mysql, please base of file')
elif engine == 'mongodb':
print('base of mongodb, please base of file')
else:
print('please base of file') return wrapper return login @auth(engine='mysql')
def home(name):
print(f"welcome {name} to home page")
time.sleep(1) @auth(engine='file')
def index():
print('welcome to index')
time.sleep(1) res = index() #username: nick
#password: 123
#base of file
#login successful
#welcome to index

注意:由于两层的装饰器,参数必须得固定位func,但是三层的装饰器解除了这个限制。我们不仅仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也就是说装饰器三层即可,多加一层反倒无用。

迭代器

迭代器:迭代的工具。

迭代是更新换代,比如你子孙繁衍;迭代也可以说成是重复,但每一次的重复都是基于上一次的结果来的,例如计算机中的迭代开发,就是基于软件的上一个版本更新。

以下代码就不是迭代,它只是单纯的重复

while True:
print('*'*10)

一、可迭代对象

定义:具有__iter__方法的对象就是可迭代对象,除了数字类型和函数类型。

注意:tuple(1)与tuple(1,)类型有区别

# x = 1.__iter__  # SyntaxError: invalid syntax

# 以下都是可迭代的对象

name = 'nick'.__iter__
lis = [1, 2].__iter__
tup = (1, 2).__iter__
dic = {'name': 'nick'}.__iter__
s1 = {'a', 'b'}.__iter__
f = open('49w.txt', 'w', encoding='utf-8')
f.__iter__
f.close()

二、迭代器对象

只有字符串列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的。因此我们得找到一个方法能让其他的可迭代对象不依赖索引取值。

定义:具有__iter____next__方法的都是迭代器对象,只有文件

缺点:

  1. 取值麻烦,只能一个一个取,并且只能往后取,值取了就没了
  2. 无法使用len()方法获取长度
# 不依赖索引的数据类型迭代取值
dic = {'a': 1, 'b': 2, 'c': 3}
iter_dic = dic.__iter__()
print(iter_dic.__next__())
print(iter_dic.__next__())
print(iter_dic.__next__())
# print(iter_dic.__next__()) # StopIteration: #a
#b
#c # 依赖索引的数据类型迭代取值
lis = [1, 2, 3]
iter_lis = lis.__iter__()
print(iter_lis.__next__())
print(iter_lis.__next__())
print(iter_lis.__next__())
# print(iter_lis.__next__()) # StopIteration: #1
#2
#3

上述的方法是非常繁琐的,我们可以使用while循环精简下。其中使用的try...except...为异常处理模块

#for循环原理

lt = [1,2,3]

lt_iter = lt.__iter__()
while 1:
try:
print(lt_iter.__next__())
except StopIteration:
break

注意一:迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象

注意二:for循环 == 迭代循环

注意三:迭代器对象使用__iter__()还是迭代器对象

【0812 | Day 13】闭包函数/装饰器/迭代器的更多相关文章

  1. 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】

    一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...

  2. Python--函数对象@命名空间与作用域@包函数@装饰器@迭代器@内置函数

    一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...

  3. python 内嵌函数, 闭包, 函数装饰器

    一.  函数内嵌 闭包 在python中,函数可以作为返回值, 可以给变量赋值. 在python中, 内置函数必须被显示的调用, 否则不会执行. #!/usr/bin/env python #-*- ...

  4. Python记录9:函数4:名称空间作用域+闭包函数+装饰器

    ''' 一: 名称空间namespaces     名称空间就是存放名字与值绑定关系的内存空间 二: 名称空间分为三种     内置名称空间:         1. 特点: 存放是python解释器自 ...

  5. Python作用域-->闭包函数-->装饰器

    1.作用域: 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部 ...

  6. Day 12 闭包函数,装饰器

    闭包函数 回顾: 1.函数对象:可以将定义在函数内的函数返回到全局使用.从而打破了函数层级限制 2.名称空间与作用域:作用域关系在函数定义阶段时就已经固定死了,与调用位置无关,即在任意位置调用函数都需 ...

  7. python3 闭包函数 装饰器

    闭包函数 1.闭:定义在函数内部的函数 2.包:内部函数引用了外部函数作用域的名字 在函数编程中经常用到闭包.闭包是什么,它是怎么产生的及用来解决什么问题呢.给出字面的定义先:闭包是由函数及其相关的引 ...

  8. python闭包函数&装饰器

    一.函数引用 函数可以被引用 函数可以被赋值给一个变量 def hogwarts(): print("hogwarts") # hogwarts() # 函数调用 print(ho ...

  9. python 复习函数 装饰器

    # 函数 —— 2天 # 函数的定义和调用 # def 函数名(形参): #函数体 #return 返回值 #调用 函数名(实参) # 站在形参的角度上 : 位置参数,*args,默认参数(陷阱),* ...

随机推荐

  1. redis 文件事件模型

    参考文献: 深入剖析 redis 事件驱动 Redis 中的事件循环 深入了解epoll (转) Redis自己的事件模型 ae EPOLL(7) Linux IO模式及 select.poll.ep ...

  2. django基础知识之HttpReqeust对象:

    HttpReqeust对象 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象 视图函数的第一个参数是HttpRequest对象 在django.http模块中定义了HttpR ...

  3. pycharm在服务器上远程调试 mac版本

    1. 首先要配置tools 2.点 +,选择SFTP, 填写 New server name:随便填写 3.然后填写 connection 和 Mapping Host:填写远程连接的ip地址 Use ...

  4. C语言学习推荐《C语言参考手册(原书第5版)》下载

  5. 浅谈 Attention 机制的理解

    什么是注意力机制? 注意力机制模仿了生物观察行为的内部过程,即一种将内部经验和外部感觉对齐从而增加部分区域的观察精细度的机制.例如人的视觉在处理一张图片时,会通过快速扫描全局图像,获得需要重点关注的目 ...

  6. Bzoj 3624: [Apio2008]免费道路 (贪心+生成树)

    Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2 1 这 ...

  7. 2019年7月22日 - LeetCode0004

    https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/ 我的解法: 我看到了那个log的要求,也第一时间想到 ...

  8. KafKa 发消息到Storm

    通过kafka客户端发送数据,由KafkaSpout进行接收消息,传输到ConsumerBolt进行实时数据处理. maven依赖 <dependencies> <!-- https ...

  9. SpringMvc返回JSON出现"$.result.currentLevel"

    "$.result.currentLevel" 问题描述 使用SpringMvc返回一个json数据的时候,会在产生的结果中出现如下的问题:"$.result.curre ...

  10. [virtualenvwrapper] 命令小结

    创建环境 mkvirtualenv env1 mkvirtualenv env2 环境创建之后,会自动进入该目录,并激活该环境. 切换环境 workon env1 workon env2 列出已有环境 ...