闭包

首先要理解函数对象的概念,其实函数名就相当于变量名,只是多了一个括号调用的功能而已.而把函数当作对象就可以让全局空间中使用局部的变量或是函数

  • 闭包就是这样,这个方法可以打破层级关系,把局部变量拿到全局进行使用,并且还可以把外部的变量x封装到f2中,然后下次直接调用f2就能够起到使用局部变量x的作用
def f1():
x = 19
def f2():
print(x)
print('from x2')
return f2 f2 = f1()
f2()
19
from x2
  • 局部变量在全局使用,但又不污染全局变量,互不干扰
x = 10
def f1(x): def f2():
print(x)
return f2 f2 = f1(5)
f2()
print(x)
5
10
  • 举一个爬虫的简单示例
import requests
def spider(url):
response = requests.get(url)
response.encoding = 'gb2312'
data = response.text
print(data) spider('http://www.xiaohuar.com')
spider('http://www.xiaohuar.com')
输出很长不复制,都是网站信息
  • 这样做每次在使用时都需要输入网址,所以用函数对象的概念改进一下
  • 同样的效果,但重复调用时变得很简单
import requests
def outter(url):
def spider():
response = requests.get(url)
response.encoding = 'gb2312'
res = response.text
return res
return spider xiaohuar = outter('http://www.xiaohuar.com')
print(xiaohuar())
print(xiaohuar())
输入很长不复制

装饰器

  • 改变代码功能的同时,不改变原有的调用方式,并且不改变原有的函数代码
# 基础功能代码块
import time def time_sleep():
time.sleep(1)
print('from sleep') time_sleep()
from sleep
  • 现在要计算这个程序停留了多久,先示例修改源代码的情况
def time_sleep():
start = time.time()
time.sleep(1)
print('from sleep')
end = time.time()
print(end-start) time_sleep()
from sleep
1.0004761219024658
  • 示例不修改源代码用一个新的函数去添加功能
def func():
start = time.time()
time_sleep()
end = time.time()
print(end-start)
func()
from sleep
1.0004405975341797

最基础的装饰器

  • 上面的写法有一个缺点,就是已经修改了原有的调用方式,会让用户很不习惯,所以我们在上面加一层装饰
def deco(func):        # 这里的func只是一个形参,用来放入你想要使用这个装饰器功能的函数
def wrapper(): # wrapper 就相当于变量名time_sleep,也就是那个假的
start = time.time()
func() # 这里是原有的time_sleep函数
end = time.time()
print(end-start)
return wrapper time_sleep = deco(time_sleep) # 这两个time_sleep并不是一个东西,但是给到用户看到的假象就是一个东西
time_sleep() # 调用这个就相当于调用wrapper(),只是伪装成了原函数
from sleep
1.0004761219024658

完善装饰器

有返回值的

def time_sleep():

    time.sleep(1)
print('from sleep') return 'lalala'
def deco(func):

    def wrapper():

        start = time.time()
res = func() # 调用函数sleep_time并且接收它的返回值
end = time.time()
print(end-start) return res # 返回sleep_time的返回值 return wrapper time_sleep = deco(time_sleep)
res = time_sleep()
print(res) # 调用函数且打印返回值
from sleep
1.000476598739624
lalala

有参数的

def time_sleep(name, age, sex='man'):
time.sleep(1)
print('from sleep')
print(name, age, sex)
return 'lalala'
def deco(func):

    def wrapper(*args, **kwargs):         # *args,**kwargs用来接收参数,打包成元祖或字典

        start = time.time()
res = func(*args, **kwargs) # *args,**kwargs用来解包成一个个的参数
end = time.time()
print(end-start) return res return wrapper time_sleep = deco(time_sleep)
res = time_sleep('leijun', 19)
print(res)
from sleep
leijun 19 man
1.0004239082336426
lalala

装饰器模版

def deco(func):

    def wrapper(*args, **kwargs):

        res = func(*args, **kwargs)

        return res

    return wrapper

语法糖

  • 写好装饰器,然后在函数上方使用"@装饰器名"来调用装饰器,让代码看上去舒服一点
  • 效果就相当于写了,伪装函数名 = 装饰器名(函数名)

登录装饰器

userinfo_dict = {'leijun': '123'}     # 用户信息可以用文件操作

def deco(func):

    def wrapper(*args, **kwargs):

        username = input('请输入用户名:').strip()
userpwd = input('请输入密码:').strip() if userinfo_dict.get(username) == userpwd:
print('登录成功')
res = func(*args, **kwargs)
return res
else:
print('登录失败')
return None return wrapper @deco
def shopping():
print('shopping') shopping()
请输入用户名:lei
请输入密码:123
登录失败
# 避免二次登录
userinfo_dict = {'leijun': '123'}     # 用户信息可以用文件操作
is_login = False # 用这个来控制用户是否需要登录 def deco(func): def wrapper(*args, **kwargs):
global is_login # 声明全局变量,否则局部的无法影响到全局的 if not is_login: # 没有登录过的
username = input('请输入用户名:').strip()
userpwd = input('请输入密码:').strip() if userinfo_dict.get(username) == userpwd:
print('登录成功')
res = func(*args, **kwargs)
is_login = True # 标记为已登录
return res
else:
print('登录失败')
return None
else:
res = func(*args, **kwargs) return res return wrapper @deco
def shopping():
print('shopping') @deco
def withopen():
print('with open') shopping()
withopen()
请输入用户名:leijun
请输入密码:123
登录成功
shopping
with open

可变类型的局部变量可以修改全局变量

l = [1, 2]
def func():
l.append(3) func()
print(l)
[1, 2, 3]

三层装饰器

  • 用来给装饰器中添加一些参数
def sanceng(name, age):
def deco(func):
print(name)
def wrapper(*args, **kwargs):
print(age)
res = func(*args, **kwargs) return res
return wrapper
return deco def haha():
print('haha') # 调用方法
deco = sanceng('leijun', 19)
haha = deco(haha)
haha() print('-' * 30)
# 调用方法二 @sanceng('leijun', 19)
def lala():
print('lala') lala()
leijun
19
haha
------------------------------
leijun
19
lala
  • 能够写下面这段代码就对闭包和装饰器有初步的了解了
is_login_dict = {'leijun': '123'}    # 用户信息,可以用文件操作进行扩展
is_login = False # 控制用户是否已登录 def auth(origin):
'''第三层装饰器''' def deco(func):
'''第二层装饰器''' def wrapper(*args, **kwargs):
'''第一层装饰器''' global is_login # 升级全局变量,便于更改 # 用户已登录的话,直接调用函数就可以了
if is_login:
res = func(*args, **kwargs)
return res # 用户没登录,但是口令不是T,不给与登录
if origin != 'T':
print('非法入侵')
return '非法入侵' # 用户没登录,但是口令是T,进行登录
username = input('请输入你的帐号>>>').strip()
userpwd = input('请输入你的密码>>>').strip() if is_login_dict.get(username) == userpwd:
print('登录成功')
is_login = True # 修改用户为已登录
res = func(*args, **kwargs)
return res
else:
print('帐号密码错误')
return None # 养成写None的习惯 return wrapper # 进入第一层 return deco # 进入第二层 @auth('T')
def shopping():
print('shopping') @auth('f')
def withopen():
print('withopen') shopping()
withopen()
请输入你的帐号>>>leijun
请输入你的密码>>>123
登录成功
shopping
withopen
  • 下面不用看
is_login_dict = {'username': None}

def auth(origin):
def login_deco(func):
'装饰器外层' def wrapper(*args, **kwargs): if not is_login_dict['username']:
username = input('请输入帐号:').strip() if username != 'leijun':
print('非法登录')
return None is_login_dict['username'] = True res = func(*args, **kwargs) return res
else:
res = func(*args, **kwargs)
return res
if origin == '1':
return wrapper
else:
print('非法入侵')
return None return login_deco @auth('1')
def shopping():
print('from shopping') @auth('0')
def register():
print('from register') shopping()
# register()
非法入侵
请输入帐号:213
非法登录
PS:这个非法入侵,是怎么出来的

day16 闭包以及装饰器(好东西)的更多相关文章

  1. Python:Day16 闭包、装饰器

    def outer(): x = 10 def inner(): #条件一.inner就是一个内部函数 print(x) #条件二.引用外部作用域的一个变量,因为x在函数外部的,所以是外部作用域的变量 ...

  2. python中的闭包和装饰器

    重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器 1.闭包 闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩 ...

  3. 高逼格利器之Python闭包与装饰器

    生活在魔都的小明,终于攒够了首付,在魔都郊区买了一套房子:有一天,小明踩了狗屎,中了一注彩票,得到了20w,小明很是欢喜,于是想干脆用这20万来装修房子吧(decoration): 整个装修过程,小明 ...

  4. python闭包与装饰器

    转自小马哥: 闭包和装饰器充分体现了Python语法糖的优雅感觉. 在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写: def valida ...

  5. python之闭包与装饰器

    python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...

  6. Python编程四大神兽:迭代器、生成器、闭包和装饰器

    生成器 生成器是生成一个值的特殊函数,它具有这样一个特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程序 ...

  7. python 闭包和装饰器

    python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...

  8. Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器

      生成器 生成器是生成一个值的特殊函数,它具有这样的特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程 ...

  9. 21.python中的闭包和装饰器

    python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...

随机推荐

  1. SQL Server UPDATE语句的用法详解

    SQL Server UPDATE语句用于更新数据,下面就为您详细介绍SQL Server UPDATE语句语法方面的知识,希望可以让您对SQL Server UPDATE语句有更多的了解. 现实应用 ...

  2. 训练1-W

    有一个长度为n(n<=100)的数列,该数列定义为从2开始的递增有序偶数,现在要求你按照顺序每m个数求出一个平均值,如果最后不足m个,则以实际数量求平均值.编程输出该平均值序列. Input 输 ...

  3. nyoj11-奇偶数分离

    奇偶数分离 时间限制:3000 ms  |  内存限制:65535 KB 难度:1 描述 有一个整型偶数n(2<= n <=10000),你要做的是:先把1到n中的所有奇数从小到大输出,再 ...

  4. [POJ2104] K – th Number (可持久化线段树 主席树)

    题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...

  5. 获取Linux ip

    第一种方法: 在终端输入命令:ifconfig ip显示为红线标注的部分. 第二种方法: 在终端输入命令:hostname -I 第三种方法: 在终端输入:ip addr show|grep &quo ...

  6. 园区IP地址规划(非常详细)

    转:https://mp.weixin.qq.com/s/Zlm7x5eunIYLAG7Sp0yVCQ 经过这些年工作,接触从几万.几十万到上亿的项目都有: 我简单总结了接触的大部分的项目,将园区网核 ...

  7. useradd常用参数介绍

    -c :新账号passwd档的说明栏 -d :新账号每次登录时所使用的home_dir,预设值为default_home内login名称,并当成登录时目录名称 -e :*账号终止日期,日期的指定格式为 ...

  8. vim+astyle安装使用

    astyle下载安装 wget https://sourceforge.net/projects/astyle/files/astyle/astyle%203.1/astyle_3.1_linux.t ...

  9. FreeMarker hello

    一.什么是 FreeMarker FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker 与 Web 容器无关,即在 Web 运行时,它并不知道  ...

  10. Strtus配置Tomcat出现问题2

    启动myeclipse的tomcat6.0有如下提示:The APR based Apache Tomcat Native library which allows optimal performan ...