python--闭包函数、装饰器
先来点补充。
x=
def foo():
print(x)
x= foo()
结果:
x=
def foo():
global x
x=
print(x) foo()
print(x)
结果:
x=
def f1():
x=
def f2():
x=
def f3():
# global x
nonlocal x
x=
f3()
print('f2内部的打印',x)
f2()
print('f1内部的打印', x) f1()
print(x)
结果:
f2内部的打印
f1内部的打印
def foo():
x =
def wrapper():
nonlocal x
x =
print(x)
return wrapper f = foo()
print(f.__closure__)
结果:
(<cell at 0x0000000002147498: int object at 0x00000000601CB440>,)
闭包函数
函数内部定义的函数,称为内部函数,该内部函数包含对外部作用域,而不是对全局作用域名字的引用,那么该内部函数称为闭包函数
name='alex'
def func():
name='egon'
def bar():
print(name)
return bar b=func()
print(b)
结果:
<function func.<locals>.bar at 0x0000000001E90730>
name='alex'
def func():
name='egon'
x=
def bar():
print(name)
print(x)
a=
b=
return bar
#
f=func() print(f.__closure__[].cell_contents)
print(f.__closure__[].cell_contents)
结果:
egon
name='alex'
def func():
name='egon'
x=
def bar():
print(name)
print(x)
a=
b=
print(bar.__closure__) func()
结果:
(<cell at 0x0000000002167498: str object at 0x00000000021EE030>, <cell at 0x00000000021674C8: int object at 0x00000000021F7350>)
闭包函数的特点:
- 自带作用域
- 延迟计算
name='alex'
def func():
def bar():
print(name)
return bar f=func()
print(f.__closure__) f()
结果:
None
alex
money=
def tell_ino(name):
print('%s have money %s' %(name,money)) tell_ino('egon') def f1():
money=
tell_ino('egon') f1()
结果:
egon have money
egon have money
money=
def f1():
money=
def tell_ino(name):
print('%s have money %s' %(name,money))
tell_ino('egon') f1()
结果:
egon have money
#包一层
def wrapper():
money=
def tell_info():
print('egon have money %s' % money)
return tell_info
tell_info=wrapper()
print(tell_info) def foo():
money=
tell_info() foo()
结果:
<function wrapper.<locals>.tell_info at 0x00000000023F0730>
egon have money
#包两层
def aaa():
name = 'egon'
def wrapper():
money =
def tell_info():
print('egon have money %s' % money)
print('my name is %s' % name)
return tell_info
return wrapper wrapper = aaa()
tell_info = wrapper()
print(tell_info.__closure__[].cell_contents)
print(tell_info.__closure__[].cell_contents)
结果: egon
我们可以看到,wrapper中引用了外围作用域变量name,但name信息存在于wrapper的定义之外。我们称name为wrapper的环境变量;
同样的,tell_info中引用了外围作用域变量money,但money信息存在于tell_info的定义之外。我们称money为tell_info的环境变量;一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。
在Python中,所谓的闭包是一个包含有环境变量的函数对象。环境变量被保存在函数对象的__closure__属性中。
'''
def tell_info(name):
print('%s have money %s' % (name,money)) def foo():
money =
tell_info('egon') foo()
结果:
NameError: name 'money' is not defined
报错NameError: name 'money' is not defined
原因:
函数的作用域关系在函数定义阶段就已经固定,与调用位置无关
无论函数在何处调用,都需要回到定义阶段去找对应的作用域关系
此例:虽然tell_info('egon')是在foo内调用并且引用money,但仍需要回到定义
tell_info的阶段去找作用域关系,而定义时tell_info引用的money就是全局的money
如果全局不存在则抛出异常NameError
'''
#定义闭包函数的基本形式:
def 外部函数名():
内部函数需要的变量
def 内部函数():
引用外部变量
return 内部函数
def deco():
x = 1
def wrapper():
print(x) return wrapper wrapper = deco() print(wrapper)
结果:
<function deco.<locals>.wrapper at 0x00000000027B0730>
def deco1():
y =
def deco():
x =
def wrapper():
print(x)
print(y) return wrapper
return deco deco = deco1()
wrapper = deco() wrapper()
结果:
from urllib.request import urlopen print(urlopen('http://www.xiaohua100.cn/').read())
print(urlopen('https://www.python.org').read()) def get(url):
return urlopen(url).read() print(get('http://www.xiaohua100.cn/'))
结果:
b'\xef\xbb\xbf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">...
b'<!doctype html>\n<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 7]> <html class="no-js ie7 lt-ie8 lt-ie9">...
b'\xef\xbb\xbf<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">...
from urllib.request import urlopen
def index(url):
# url='http://www.xiaohua100.cn/'
def get():
return urlopen(url).read()
return get xiaohua=index('http://www.xiaohua100.cn/') python=index('https://www.python.org') baidu=index('http://www.baidu.com') print(python())
结果:
b'<!doctype html>\n<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 7]> <html class="no-js ie7 lt-ie8 l
t-ie9">...
装饰器
'''
一:开放封闭原则,对扩展是开放的,对修改是封闭的
二:装饰器,装饰器本质可以是任意可调用对象,被装饰的对象也可以是任意
可调用对象,
装饰器的功能是:
在不修改被装饰对象源代码以及调用方式的前提下为期添加新功能
原则:
1.不修改源代码
2.不修改调用方法
目标:添加新功能
'''
import time
import random
#装饰器
def timmer(func):
# func=index
def wrapper():
start_time = time.time()
func() #index()
stop_time = time.time()
print('run time is %s' % (stop_time-start_time))
return wrapper
#被装饰函数
def index():
time.sleep(random.randrange(, ))
print('welcome to index page') def home():
time.sleep(random.randrange(, ))
print('welcome to HOME page') index = timmer(index) #index=wrapper
home = timmer(home) index() #wrapper()
home()
结果:
welcome to index page
run time is 1.0000572204589844
welcome to HOME page
run time is 1.0000572204589844
#装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字
import time
import random
#装饰器
def timmer(func):
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' % (stop_time-start_time))
return wrapper
#被装饰函数
@timmer #index=timmer(index)
def index():
time.sleep(random.randrange(, ))
print('welcome to index page')
@timmer #home=timmer(home)
def home():
time.sleep(random.randrange(, ))
print('welcome to HOME page') index() #wrapper()
home()
结果:
welcome to index page
run time is 4.0002288818359375
welcome to HOME page
run time is 1.0000574588775635
#加多个装饰器
定义阶段外部函数的执行顺序是自下而上
调用阶段内部函数的执行顺序是自上而下
import time
import random
#装饰器
def timmer(func):
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' % (stop_time-start_time))
return wrapper
def auth(func):
def deco():
name = input('name: ')
password = input('password: ')
if name == 'egon' and password == '':
print('login successful')
func() #wrapper()
else:
print('login err')
return deco #被装饰函数
@auth #index=auth(wrapper) #index=deco #index=auth(wrapper) #index=deco
@timmer #index=timmer(index) #index=wrapper
def index():
# time.sleep(random.randrange(,))
time.sleep()
print('welcome to index page') @timmer
@auth
def home():
time.sleep(random.randrange(, ))
print('welcome to HOME page') index() #deco()
home()
结果:
name: egon
password:
login successful
welcome to index page
run time is 3.000171661376953
name: egon
password:
login successful
welcome to HOME page
run time is 5.638322591781616
#装饰器修订
import time
import random
#装饰器
def timmer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('run time is %s' % (stop_time-start_time))
return res
return wrapper
#被装饰函数 @timmer
def index():
time.sleep(random.randrange(, ))
print('welcome to index page')
@timmer
def home(name):
time.sleep(random.randrange(, ))
print('welcome to %s HOME page' % name)
return res1 = index()
print('index return %s' % res1)
res2 = home('egon') #wraper()
print('home return %s' % res2)
结果:
welcome to index page
run time is 1.0000572204589844
index return None
welcome to egon HOME page
run time is 2.0001142024993896
home return
作业:
一:编写函数,(函数执行的时间是随机的)
二:编写装饰器,为函数加上统计时间的功能
三:编写装饰器,为函数加上认证的功能 四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式 五:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果 六:为题目五编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中 七:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
答案:
# 一:编写函数,(函数执行的时间是随机的)
# import time
# import random
# def index():
# time.sleep(random.randrange(,))
# print('welcome to index page')
#
# index() # 二:编写装饰器,为函数加上统计时间的功能
# import time
# import random
# def timmer(func):
# # func=index
# def wrapper():
# start_time = time.time()
# func() #index()
# stop_time = time.time()
# print('running time is %s'%(stop_time -start_time ))
# return wrapper
#
# @timmer
# def index():
# time.sleep(random.randrange(,))
# print('welcome to index page')
#
# index() # 三:编写装饰器,为函数加上认证的功能
# import time
# import random
# def auth(func):
# #func=register
# def wrapper():
# username=input('name: ')
# password=input('password: ')
# if username =='kaylee' and password =='':
# print('login successful')
# func()
# else:
# print('login error')
# return wrapper
#
# @auth
# def register():
# time.sleep(random.randrange(,))
# print('welcome to register page')
#
# register() # 四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
# 注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式
# user_dic={'egon':'',
# 'kaylee':'',
# 'lily':''}
# with open('decorate2.txt','w',encoding='utf-8') as f:
# f.write(str(user_dic)) # decorate2_path=r'C:\Users\Administrator\PycharmProjects\untitled\decorate2.txt'
# # with open('decorate2.txt','r',encoding='utf-8') as f:
# # res=f.read()
# # user_dic=eval(res)
#
# login_dic={'user':None,
# 'status':False}
# def auth(func):
# def wrapper(*args,**kwargs):
# if login_dic['user'] and login_dic['status']:
# res = func(*args, **kwargs)
# return res
# name=input('name: ')
# psw=input('password: ')
# with open(decorate2_path,'r',encoding='utf-8') as f:
# user_dic=eval(f.read())
#
# if name in user_dic and psw == user_dic[name]:
# print('login ok')
# login_dic['user']=name
# login_dic['status']=True
# res=func(*args,**kwargs)
# return res
# else:
# print('login error')
#
# return wrapper
#
# @auth
# def index():
# print('welcome to index')
# @auth
# def home(name):
# print('welcome to %s home page'%name)
#
# index()
# home('egon') # 五:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
# from urllib.request import urlopen
#
# def get(url):
# return urlopen(url).read()
#
# print(get('http://www.baidu.com')) # 六:为题目五编写装饰器,实现缓存网页内容的功能:
# 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
# from urllib.request import urlopen
# import os
#
# cache_path=r'C:\Users\Administrator\PycharmProjects\untitled\cache.txt'
# def make_cache(func):
# def wrapper(*args,**kwargs):
# if os.path.getsize(cache_path):
# print('\033[45m========>有缓存\033[0m')
# with open(cache_path,'rb') as f:
# res=f.read()
# else:
# res=func(*args,**kwargs)
# with open(cache_path,'wb') as f:
# f.write(res)
# return res
# return wrapper
#
# @make_cache
# def get(url):
# return urlopen(url).read()
#
# print('=========>first')
# print(get('https://www.python.org'))
# print('=========>second')
# print(get('https://www.python.org'))
# print('=========>third')
# print(get('https://www.python.org')) #七:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
func_dic={}
def deco(key):
def deco2(func):
func_dic[key]=func
return deco2 @deco('f1')
def f1():
print('from f1') @deco('f2')
def f2():
print('from f2') @deco('f3')
def f3():
print('from f3') print(func_dic ) while True:
cmd=input('>>: ').strip()
if cmd in func_dic:
func_dic[cmd]()
python--闭包函数、装饰器的更多相关文章
- python闭包函数&装饰器
一.函数引用 函数可以被引用 函数可以被赋值给一个变量 def hogwarts(): print("hogwarts") # hogwarts() # 函数调用 print(ho ...
- python基础—函数装饰器
python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...
- python 闭包和装饰器
python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...
- python 复习函数 装饰器
# 函数 —— 2天 # 函数的定义和调用 # def 函数名(形参): #函数体 #return 返回值 #调用 函数名(实参) # 站在形参的角度上 : 位置参数,*args,默认参数(陷阱),* ...
- 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- python闭包与装饰器
转自小马哥: 闭包和装饰器充分体现了Python语法糖的优雅感觉. 在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写: def valida ...
- 详解Python闭包,装饰器及类装饰器
在项目开发中,总会遇到在原代码的基础上添加额外的功能模块,原有的代码也许是很久以前所写,为了添加新功能的代码块,您一般还得重新熟悉源代码,稍微搞清楚一点它的逻辑,这无疑是一件特别头疼的事情.今天我们介 ...
- 高逼格利器之Python闭包与装饰器
生活在魔都的小明,终于攒够了首付,在魔都郊区买了一套房子:有一天,小明踩了狗屎,中了一注彩票,得到了20w,小明很是欢喜,于是想干脆用这20万来装修房子吧(decoration): 整个装修过程,小明 ...
- Python—闭包和装饰器
闭包 定义:内部函数对外部函数变量的引用,则将该函数与用到的变量称为闭包. 闭包必须满足以下三个条件: 必须有一个内嵌函数. 内嵌函数必须引用外部函数中的变量. 外部函数返回值必须是内嵌函数的引用. ...
- Python 简明教程 --- 22,Python 闭包与装饰器
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 当你选择了一种语言,意味着你还选择了一组技术.一个社区. 目录 本节我们来介绍闭包与装饰器. 闭包与 ...
随机推荐
- 每天一个linux命令:more(13)
more more命令是一个基于vi编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持vi中的关键字定位操作.more名单中内置了若干快捷键,常用的有H(获得帮助信息),Enter(向下翻 ...
- iOS设计模式之装饰者模式
一,什么是装饰模式 模式定义 装饰者包含被装饰者的所有接口和引用,方法实现完全是引用调用自己的方法,在装饰者子类添加新功能. 注释: Category不要重写被装饰对象的方法,否则改变了被装饰对象的行 ...
- mysql经典面试题之学生成绩表
需要数据库表1.学生表 Student(SID,Sname,Sage,Ssex) --SID 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 2.课程表 Course(CID, ...
- Vue&webpack入门实践
目录 1. 下载安装Vue 2. Vue 2.1 Vue要素 2.2 指令 2.3 组件化 2.4 vue-router 3. webpack 3.1 webpack简介 3.2 四个核心概念 3.3 ...
- 安装mysql5.6.24解压版
第一步:配置环境变量 第二步:修改 my-default.ini 文件 找到mysql 文件夹中的my-default,ini 修改成如下图 如果不修改直接运行cmd net start m ...
- JS中基本数据类型和引用类型最根本的区别
栈内存和堆内存:https://segmentfault.com/a/1190000015118062 https://segmentfault.com/a/1190000016389376 变量:内 ...
- Objective-C Properties 详解
关于Objective-C 的property,很多iOS开发的新手都会很迷惑,也会包括有经验的iOS开发程序员, 因为Objective-C的property,说多不多,说少却也不少,从MRR(Ma ...
- LeetCode刷题: 【120】三角形最小路径和
1. 题目: 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小 ...
- VB - 循环
循环控制语句有for……next循环.for……each循环.do……while循环.do……until循环.while循环五种形式. 1. 在使用循环控制语句前,首先要对循环条件进行判断,如果循环次 ...
- JNDI数据源的配置及使用
数据源的作用JDBC操作的步骤: 1. 加载驱动程序 2. 连接数据库 3. 操作数据库 4. 关闭数据库,释放连接 也就是说,所有的用户都需要经过此四步进行操作,但是这四步之中有三步对所有人 ...