闭包函数

1.闭:定义在函数内部的函数 2.包:内部函数引用了外部函数作用域的名字

在函数编程中经常用到闭包。闭包是什么,它是怎么产生的及用来解决什么问题呢。给出字面的定义先:
闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)(想想Erlang的外层函数传入一个参数a, 内层函数依旧传入一个参数b, 内层函数使用a和b, 最后返回内层函数)
这个从字面上很难理解,特别对于一直使用命令式语言进行编程的程序员们。本文将结合实例代码进行解释。
函数是什么都知道:函数只是一段可执行代码,编译后就“固化”了,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数了。
在函数式编程语言中,函 数是一等公民(First class value:第一类对象,我们不需要像命令式语言中那样借助函数指针,委托操作函数),函数可以作为另一个函数的参数或返回值,可以赋给一个变量。
函数可 以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。如:# def outter():
# x = 111
# def inner():
# print(x)
# return inner
# res = outter() # res就是inner函数内存地址 # def func():
# x = 333
# res()
# func() python中的闭包从表现形式上定义(解释)为:
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
这个定义是相对直白的,好理解的,不像其他定义那样学究味道十足(那些学究味道重的解释,在对一个名词的解释过程中又充满了一堆让人抓狂的其他陌生名词,不适合初学者)。下面举一个简单的例子来说明。 # 给函数体传值的第一种方式 传参
# def index1(username):
# print(username)
#
# # 给函数体传参的第二种方式 闭包
# def outter(x,y):
# # x = 1
# # y = 40
# def my_max():
# if x > y:
# return x
# return y
# return my_max
# res1 = outter(1,40) # res就是my_max函数的内存地址
# print(res1())
# print(res1())
# print(res1())
# res2 = outter(90,200)
# print(res2())
# print(res2())
# print(res2()) import requests # 第一个直接给函数传参
url1 = 'https://www.baidu.com'
url2 = '...'
def my_get(url):
response = requests.get(url)
if response.status_code == 200:
print(len(response.text)) my_get(url1)
my_get(url1)
my_get(url1)
my_get('https://www.baidu.com')
my_get('https://www.baidu.com')
my_get('https://www.baidu.com') # 第二种给函数传参的方式 闭包
def outter(url):
# url = 'https://www.jd.com'
def my_get():
response = requests.get(url)
if response.status_code == 200:
print(len(response.text))
return my_get
my_jd = outter('https://www.jd.com')
my_jd()
my_jd()
my_baidu = outter('https://www.baidu.com')
my_baidu()
my_baidu()
my_baidu()
二,使用闭包注意事项 1,闭包中是不能修改外部作用域的局部变量的
除非事先声明globl nonlocal 变量类型
三,作用
说了这么多,不免有人要问,那这个闭包在实际的开发中有什么用呢?闭包主要是在函数式开发过程中使用。以下介绍两种闭包主要的用途。
 
用途1,当闭包执行完后,仍然能够保持住当前的运行环境。
用途2,闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行。
 
 
 

装饰器:

器:就是一个工具
装饰:给被装饰对象添加新的功能

为什么要用装饰器
开放封闭原则:
开放:对扩展开放
封闭:对修改封闭

装饰器(可调用对象)必须遵循的两个原则:
1.不改变被装饰对象源代码
2.不改变被装饰对象(可调用对象)调用方式
def index():
pass
index()

如何用

from functools import wraps

def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
这里我们写一个日志的装饰器
from functools import wraps def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging @logit
def addition_func(x):
"""Do some math."""
return x + x result = addition_func(4)
# Output: addition_func was called

更进一步 我们可以 继续封装装饰器 如下

from functools import wraps

def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile,并写入内容
with open(logfile, 'a') as opened_file:
# 现在将日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator @logit()
def myfunc1():
pass myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串 @logit(logfile='func2.log')
def myfunc2():
pass myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
装饰器类
现在我们有了能用于正式环境的logit装饰器,但当我们的应用的某些部分还比较脆弱时,异常也许是需要更紧急关注的事情。
比方说有时你只想打日志到一个文件。而有时你想把引起你注意的问题发送到一个email,同时也保留日志,留个记录。这是一个使用继承的场景,但目前为止我们只看到过用来构建装饰器的函数。
幸运的是,类也可以用来构建装饰器。那我们现在以一个类而不是一个函数的方式,来重新构建logit。 from functools import wraps class logit(object):
def __init__(self, logfile='out.log'):
self.logfile = logfile def __call__(self, func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile并写入
with open(self.logfile, 'a') as opened_file:
# 现在将日志打到指定的文件
opened_file.write(log_string + '\n')
# 现在,发送一个通知
self.notify()
return func(*args, **kwargs)
return wrapped_function def notify(self):
# logit只打日志,不做别的
pass

装饰器的执行顺序检测

from functools import wraps
def outter(func):
@wraps(func) # 装饰器修复技术
def inner(*args,**kwargs):
"""
我是inner函数
:param args:
:param kwargs:
:return:
"""
print('执行被装饰函数之前 你可以执行的操作')
res = func(*args,**kwargs)
print('执行被装饰函数之后 你可以执行的操作')
return res
return inner @outter # index = outter(最原始的index内存地址)
def index():
"""
这是index函数
:return:
"""
pass

print(index)
print(help(index)) # 查看函数的注释
print(index.__name__) # 查看函数名字符串形式
index()
"""
用户查看被装饰函数的函数名的时候查看到的就是被装饰函数本身
用户查看被装饰函数的注释的时候查看到的就是被装饰函数的注释
"""

def outter1(func1):
print('加载了outter1')
def Decorators1(*args,**kwargs):
print('执行了Decorators1')
res1=func1(*args,**kwargs)
print('执行了func1')
return res1
return Decorators1
def outter2(func2):
print('加载了outter2')
def Decorators2(*args,**kwargs):
print('执行了Decorators2')
res2=func2(*args,**kwargs)
print('执行了func2')
return res2
return Decorators2
def outter3(func3):
print('加载了outter3')
def Decorators3(*args,**kwargs):
print('执行了Decorators3')
res3=func3(*args,**kwargs)
print('执行了func3')
return res3
return Decorators3
@outter1 # index = outter1(wapper2)
@outter2 # Decorators2 = outter2(Decorators3)
@outter3 # Decorators3 = outter3(最原始的index函数内存地址)
def index():
print('from index') """
加载了outter3
加载了outter2
加载了outter1 执行了Decorators1
执行了Decorators2
执行了Decorators3
from index
"""
index()

执行结果为:

加载了outter3
加载了outter2
加载了outter1
执行了Decorators1
执行了Decorators2
执行了Decorators3
from index
执行了func3
执行了func2
执行了func1

Process finished with e

python3 闭包函数 装饰器的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. 【0812 | Day 13】闭包函数/装饰器/迭代器

    目录 闭包函数 无参装饰器 有参装饰器 迭代器 闭包函数 一.什么是闭包? 闭包指的是:函数内部函数对外部作用域而非全局作用域的引用. def outter(): x = 1 def inner(): ...

  7. python闭包函数&装饰器

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

  8. 【python3】 函数 装饰器

    第一步 : 了解装饰器 装饰器模式,重点在于装饰,装饰的核心仍是被装饰的对象. 举一个栗子:我今天穿了一件短袖,但是突然一阵风,短袖没办法为我御寒,我想到的办法是将短袖变得更厚更长,但是改造之后,它就 ...

  9. python 复习函数 装饰器

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

随机推荐

  1. NodeJS——在Sublime中配置NodeJS执行环境

    这种方式比在DOS窗中直接执行更加高效!!! nodejs 1.运行Sublime,菜单上找到Tools ---> Build System ---> new Build System 2 ...

  2. JAVA自学笔记(1)

    JAVA入门级知识储备(一) 1.Scanner的欢乐接收 import java.util.Scanner; public class first { public static void main ...

  3. Linux passwd 提权

    利用条件,passwd 可写 ls -al /etc/passwd 利用方式: 生成密钥  openssl passwd -1 -salt test 123456 写入passwd echo 'tes ...

  4. 七个生产案例告诉你BATJ为何选择ElasticSearch!应用场景和优势!

    本文来源于公众号[胖滚猪学编程],转载请注明出处. 从今天开始,想和你一起死磕ElasticSearch,学习分布式搜索引擎,跟着胖滚猪就对了! 既然是ES的第一课,那么最重要的是让你爱上它!不想说那 ...

  5. 一篇文章看清楚 Linux 的职业发展方向

    手机.汽车.甚至宇宙飞船,在今天的科技世界中,你几乎到处都能看到 Linux 的身影.前两天 SpaceX 成功将宇航员送入太空的猎鹰9号火箭与龙飞船用的也是 Linux的操作系统.身处与 Linux ...

  6. [验证码识别技术] 字符型验证码终结者-CNN+BLSTM+CTC

    验证码识别(少样本,高精度)项目地址:https://github.com/kerlomz/captcha_trainer 1. 前言 本项目适用于Python3.6,GPU>=NVIDIA G ...

  7. 高性能可扩展mysql 笔记(四)项目分区表演示

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 登录日志的分区 如何为Customer_login_log表分区? 从以下两个业务场景入手: 用户每次登 ...

  8. Java实现 蓝桥杯 算法训练 审美课

    算法训练 审美课 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 <审美的历程>课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手.老师 ...

  9. Linux文件搜索命令locate、which、grep详解

    命令locate详解 命令locate,其基本功能是在文件资料库中可以快速的搜索系统文件,占用系统资源很少,例如:locate my.cnf 还可以使用locate -i [文件名],不区分大小写进行 ...

  10. arduino 的analogRead() 和analogWrite()

    模拟输入analogRead()函数的返回值范围是0 到1023; 而模拟输出analogWrite()函数的输出值范围是0 到255; 所以: val = analogRead(potpin); / ...