python3 闭包函数 装饰器
闭包函数
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.不改变被装饰对象(可调用对象)调用方式
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 闭包函数 装饰器的更多相关文章
- 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- python 内嵌函数, 闭包, 函数装饰器
一. 函数内嵌 闭包 在python中,函数可以作为返回值, 可以给变量赋值. 在python中, 内置函数必须被显示的调用, 否则不会执行. #!/usr/bin/env python #-*- ...
- Python记录9:函数4:名称空间作用域+闭包函数+装饰器
''' 一: 名称空间namespaces 名称空间就是存放名字与值绑定关系的内存空间 二: 名称空间分为三种 内置名称空间: 1. 特点: 存放是python解释器自 ...
- Python作用域-->闭包函数-->装饰器
1.作用域: 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部 ...
- Day 12 闭包函数,装饰器
闭包函数 回顾: 1.函数对象:可以将定义在函数内的函数返回到全局使用.从而打破了函数层级限制 2.名称空间与作用域:作用域关系在函数定义阶段时就已经固定死了,与调用位置无关,即在任意位置调用函数都需 ...
- 【0812 | Day 13】闭包函数/装饰器/迭代器
目录 闭包函数 无参装饰器 有参装饰器 迭代器 闭包函数 一.什么是闭包? 闭包指的是:函数内部函数对外部作用域而非全局作用域的引用. def outter(): x = 1 def inner(): ...
- python闭包函数&装饰器
一.函数引用 函数可以被引用 函数可以被赋值给一个变量 def hogwarts(): print("hogwarts") # hogwarts() # 函数调用 print(ho ...
- 【python3】 函数 装饰器
第一步 : 了解装饰器 装饰器模式,重点在于装饰,装饰的核心仍是被装饰的对象. 举一个栗子:我今天穿了一件短袖,但是突然一阵风,短袖没办法为我御寒,我想到的办法是将短袖变得更厚更长,但是改造之后,它就 ...
- python 复习函数 装饰器
# 函数 —— 2天 # 函数的定义和调用 # def 函数名(形参): #函数体 #return 返回值 #调用 函数名(实参) # 站在形参的角度上 : 位置参数,*args,默认参数(陷阱),* ...
随机推荐
- 跟着阿里学JavaDay04——Java基础语法(二)
一.Java运算符 运算符的简介 所有的程序开发,都是对数字的进行处理.而对数字的处理,一定会存在所谓的操作模式,而这些操作模式就被称为运算符. 算术运算符 对于算术运算符,我们主要掌握++,--的运 ...
- .NET编程5月小结 - Blazor, Unity, Dependency Injection
本文是我在5月份看到的一些有趣的内容的集合.在这里你可以找到许多有关Blazor.ASPNET Core的学习资源和示例项目,有关在Unity中使用Zenject进行单元测试的博客,有关Unity项目 ...
- Java实现 蓝桥杯 算法提高 矩阵乘法(暴力)
试题 算法提高 矩阵乘法 问题描述 小明最近刚刚学习了矩阵乘法,但是他计算的速度太慢,于是他希望你能帮他写一个矩阵乘法的运算器. 输入格式 输入的第一行包含三个正整数N,M,K,表示一个NM的矩阵乘以 ...
- Java实现 LeetCode 654 最大二叉树(递归)
654. 最大二叉树 给定一个不含重复元素的整数数组.一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素. 左子树是通过数组中最大值左边部分构造出的最大二叉树. 右子树是通过数组中最 ...
- Java实现 LeetCode 394 字符串解码
394. 字符串解码 给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次.注意 k ...
- Java实现 LeetCode 52 N皇后 II
52. N皇后 II n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n,返回 n 皇后不同的解决方案 ...
- DOM 元素的循环遍历
博客地址:https://ainyi.com/89 获取 DOM 元素的几种方式 get 方式: getElementById getElementsByTagName getElementsBy ...
- Spring Cloud 系列之 Alibaba Nacos 注册中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Alibaba Nacos 注册中心(一) 本篇文章讲解 Nacos 注册中心集群环境搭建. Nacos 集群环境搭建 ...
- iic uart spi
第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynch ...
- Java实现定时任务的三种简单方法
第一种方法: /** * 先定义一个任务每天执行的时间点,再写一个死循环,不断地拿当前时间和事先定义的时间去比对,若到时间则执行任务 */ @Test public void test1() { St ...