Python-闭包和修饰器
2019-07-14 本文已影响0人
徐弱西
作用域
# 作用域:名字起作用的范围
# 作用:解决同名字可以共存问题 - 不同作用域相同名字的值都能在其作用域范围下进行使用
'''
四种作用域: LEGB
Built-in:内置作用域 - 所有文件所有地方都可以被访问
Global:全局作用域 - 在当前文件的所有位置
Enclosing:嵌套作用域 - 自身内部与内部的子函数
Local:局部作用域 - 只有自身内部
'''
# 加载顺序:Built-in > Global > Enclosing > Local
# 访问(查找)顺序:报错 < Built-in < Global < Enclosing < Local
# 作用范围:Built-in > Global > Enclosing > Local
闭包
# 闭包:定义在函数内部的函数,这个内部的函数就是闭包
# 应用场景:
# 1.可以去使用其他函数的内部变量,且还可以保证调用位置不变(闭包的函数对象作为那个函数的返回值)
def outer():
count = 3000
def fn():
print(count) # 能使用outer内部的变量count
return fn
# 还是在外界调用
outer()() # outer()() => fn() => 调用fn
# 2.延迟执行(外层函数可以为内存函数传递参数)
import requests
def outer(url):
def show_html():
response = requests.get(url)
print(response.text)
return show_html
# 制作 爬百度与新浪的 函数对象
show_baidu = outer('https://www.baidu.com')
show_sina = outer('https://www.sina.com.cn')
# 延迟到需求来了,需要爬百度,就用百度函数对象,需要爬新浪,就用新浪函数对象
show_baidu()
show_sina()
show_baidu()
code:
# closure:闭包
# 闭包:定义在函数内部的函数,这个内部的函数就是闭包
# 应用场景:
# 1.可以去使用其他函数的内部变量,且还可以保证调用位置不变(闭包的函数对象作为那个函数的返回值)
def outer():
count = 3000
def fn():
print(count) # 能使用outer内部的变量count
return fn
# 还是在外界调用
outer()() # outer()() => fn() => 调用fn
# 2.延迟执行(外层函数可以为内存函数传递参数)
import requests
# def show_html(url):
# response = requests.get(url)
# print(response.text)
#
# show_html('https://www.baidu.com')
# show_html('https://www.baidu.com')
# show_html('https://www.sina.com.cn')
def outer(url):
def show_html():
response = requests.get(url)
print(response.text)
return show_html
# 制作 爬百度与新浪的 函数对象
show_baidu = outer('https://www.baidu.com')
show_sina = outer('https://www.sina.com.cn')
# 延迟到需求来了,需要爬百度,就用百度函数对象,需要爬新浪,就用新浪函数对象
show_baidu()
show_sina()
show_baidu()
装饰器
# 装饰器:装饰器就是闭包的一个应用场景
# -- 外层函数与内存函数形成的闭包结构的一种综合使用
# 重点:开放封闭原则
# 开放:拓展功能的点是开放的 - 可以为之前的函数添加新功能
# 封闭:1.不能改变原函数的源代码 2.还有通过原函数的函数对象来调用函数
def huaping():
print('插花功能')
temp = huaping
def my_huaping():
temp()
print('观赏功能')
huaping = my_huaping
huaping()
# ----------------------------------------
def huaping():
print('插花功能')
def outer(temp): # temp = huaping
def my_huaping():
temp()
print('观赏功能')
return my_huaping
huaping = outer(huaping) # huaping = my_huaping
huaping()
# ----------------------------------------------
def outer(temp): # temp = huaping
def my_huaping():
temp()
print('观赏功能')
return my_huaping
@outer # huaping = outer(huaping)
def huaping():
print('插花功能')
huaping()
# ------------------------------------------
# 被装饰的函数可能有参有返:装饰器模板,可以满足所有参数,且能装饰原函数返回值
def outer(func): # temp = huaping
def inner(*args, **kwargs):
pass
res = func(*args, **kwargs)
pass
return res
return inner
@outer
def any_method():
pass
code:
# 装饰器:装饰器就是闭包的一个应用场景
# -- 外层函数与内存函数形成的闭包结构的一种综合使用
# def huaping():
# print('插花功能')
# 需求:如何拓展一个原有函数的功能
# -- 修改源代码
# -- 创建一个包含该功能和其他新功能的新函数
# 开放封闭原则:
# 开放:拓展功能的点是开放的 - 可以为之前的函数添加新功能
# 封闭:1.不能改变原函数的源代码 2.还有通过原函数的函数对象来调用函数
# 错误一:修改了源代码
# def huaping():
# print('插花功能')
# print('观赏功能')
# huaping()
# 错误二:改变了调用方式
# def huaping():
# print('插花功能')
# def my_huaping(fn):
# fn()
# print('观赏功能')
# my_huaping(huaping)
# 装饰器:满足开放封闭原则还能拓展新功能,简单
'''
def huaping():
print('插花功能')
temp = huaping
# temp = '呵呵'
def my_huaping():
temp()
print('观赏功能')
huaping = my_huaping
huaping()
'''
# 装饰器演变一:
'''
def huaping():
print('插花功能')
def outer(fn): # fn = huaping
# temp = huaping # 可以提取到实参对形参传递
def my_huaping():
fn()
print('观赏功能')
return my_huaping
huaping = outer(huaping) # 要整合该条逻辑
huaping()
'''
# 装饰器演变二:
def outer(fn): # fn = 原功能的huaping
def my_huaping(): # my_huaping => 新功能的huaping
fn()
print('观赏功能')
return my_huaping
@outer # huaping = outer(huaping) 被装饰的函数对象 = 装饰器外层函数对象(被装饰的函数对象)
def huaping():
print('插花功能')
huaping() # 被装饰后的my_huaping
装饰器案例
# 为登录功能添加账号检验功能:必须是3个及以上英文字母组成
def check_user(func):
def inner(user, pwd):
if not (user.isalpha() and len(user) >= 3):
return '账号不合法'
res = func(user, pwd)
return res
return inner
# 为登录功能添加密码检验功能:必须是3个及以上英文字母或数字组成
def check_pwd(func):
def inner(*args, **kwargs):
pwd = args[1]
if not (pwd.isalnum() and len(pwd) >= 3):
return '密码不合法'
res = func(*args, **kwargs)
return res
return inner
# 对登录结果的修饰装饰器:True=>登录成功 False=>登录失败
def change_res(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
if res == True:
return '登录成功'
return '登录失败'
return inner
# 装饰器被执行的过程是从上至下
@check_user # login = check_user(func=login) = inner
@check_pwd
@change_res
def login(user, pwd): # 被装饰的函数对象
if user == 'owen' and pwd == '123':
return True
return False
user = input('user: ')
pwd = input('pwd: ')
res = login(user, pwd)
print(res)
code:
# 为登录功能添加账号检验功能:必须是3个及以上英文字母组成
def check_user(func):
def inner(user, pwd):
if not (user.isalpha() and len(user) >= 3):
return '账号不合法'
res = func(user, pwd)
return res
return inner
# 为登录功能添加密码检验功能:必须是3个及以上英文字母或数字组成
def check_pwd(func):
def inner(*args, **kwargs):
pwd = args[1]
if not (pwd.isalnum() and len(pwd) >= 3):
return '密码不合法'
res = func(*args, **kwargs)
return res
return inner
# 对登录结果的修饰装饰器:True=>登录成功 False=>登录失败
def change_res(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
if res == True:
return '登录成功'
return '登录失败'
return inner
@check_user # login = check_user(func=login) = inner
@check_pwd
@change_res
def login(user, pwd):
if user == 'owen' and pwd == '123':
return True
return False
user = input('user: ')
pwd = input('pwd: ')
res = login(user, pwd)
print(res)
# 装饰器:固定写法
def outer(func):
def inner(*args, **kwargs):
pass
res = func(*args, **kwargs)
pass
return res
return inner
@outer
def f1(): # 任意函数
pass
f1()