今日内容
1.函数对象
2.名称空间与作用域
3.函数的嵌套调用与闭包
4.装饰器
一、函数对象
1.1 定义
函数名存放的就是函数地址,所以函数名也就是对象,称之为函数对象
1.2 函数对象的应用
1.可以直接被引用
2.可以当作函数参数传数
3.可以作为函数的返回值
4.可以作为容器类型的元素
def fn():
num = 10
print('fn function run')
# 直接被引用
func = fn
fn()
func()
案例:四则运算
def add(n1, n2):
return n1 + n
def sub(n1, n2): # subtraction 减法
return n1 - n2
def mul(n1, n2): # multiplication 乘法
return n1 * n2
def div(n1, n2): # division 除法
return n1 / n2
method_map = {
'add': add,
'sub': sub,
'mul': mul,
'div': div
}
def computed(fn):
if fn in method_map:
return method_map[fn]
else:
return add
def func():
cmd = input("方法名:")
method = computed(cmd)
result = method(100, 20)
print(result)
func()
二、名称空间
2.1 三种名称空间
built-in:内置名称空间,系统级,一个,随解释器执行而产生,解释器停止而销毁
global:全局名称空间,文件级,多个,随所属文件加载而产生,文件运行完毕而销毁
local:局部名称空间,函数级,多个,随所属函数执行而产生,函数执行完毕而销毁
注:加载顺序:built-in > global > local
num = 10
def fn2():
num = 20
print("this is fn2", num)
def fn3():
num = 30
print("this is fn3", num)
fn2() # this is fn2 20
fn3() # this is fn3 30
print(num) # 10
三、作用域
3.1 LEGB
不同作用域之间名字不冲突,以达到名字的重用
直接查找顺序: Local -> Enclosing -> global -> built-in
built-in : 内置作用域,所有函数
global:全局作用域,当前文件所有函数
enclosing:嵌套作用域,当前函数
local:局部作用域
len = 10
def outer():
len = 20
def inner():
len = 30
print('1', len)
inner()
print('2', len)
outer()
print('3', len) # 10 global --> built-in
del len
print('4', len) # len地址--》built-in
nonlocal:
作用:将L与E的名字统一(E中的名字需要提前定义)
应用场景:如果想在被嵌套的函数中修改外部函数变量(名字)的值
案例:
def outer():
num = 10
print(num) # 10
def inner():
nonlocal num
num = 20
print(num) # 20
inner()
print(num) # 20
outer()
# 第三行打印的 num ,是上一行定义的num
# 由于第五行用 nonlocal 声明了,所以inner里面的num和outer里面定义的num指代的是同一个东西
# 第七行打印的 num ,在第六行重新赋值(num指向的内存地址发生改变)
四、函数嵌套
将函数直接定义到另一个函数内部就可以使用外部函数中的名字
def outer():
num = 20
def inner():
print(num) # inner 可以直接使用outer中的名字
inner()
outer()
五、闭包
函数嵌套(格式稍作改良)
inner : 可以使用outer的局部变量
def outer():
num = 10
def inner:
print(num)
return inner
fn = outer()
fn()
# 案例一:外部函数可以为闭包传递参数
import time
def download():
print('开始下载...')
time.sleep(2)
print('完成下载...')
data = ""
outer(data)
# 传参
def outer(data):
def inner():
# 保存,播放,删除等操作
print("闭包打印:", data)
inner()
download()
# 案例二:延迟执行
import requests
def outer(url):
def get_html():
html = requests.get(url)
print(html.text)
return get_html
# 先预定义多个爬虫方法,爬页面操作并未执行
baidu = outer('https://www.baidu.com')
python = outer('https://www.python.org')
sina = outer('https://www.sina.com.cn')
# 什么时候想爬什么页面就调用指定页面的爬虫方法
baidu()
sina()
2019.04.02 更新
四、装饰器
4.1 什么是装饰器
名字上来看,就是用来装饰的东西
从使用上来看,用来‘装饰’其他函数的函数,可以在原先函数功能基础上添加新的功能
4.2 开放封闭原则
在不改变调用方式和源码上增加功能
1.不能修改被装饰对象(函数)的源代码(封闭)
2.不能更改被修饰对象(函数)的调用方式,且能达到增加功能的效果(开放)
4.3 装饰器语法格式
def outer(fn):
def inner(*args,**kwargs):
#实现的功能
result = fn(*args,**kwargs)
#实现的功能
return result
return inner
4.4 案例们
4.4.1 实现原理
def fn():
print("这是最初的函数!")
# 装饰器
def outer(func):
def inner():
func()
print("打印一行给你看看,这就是添加的新功能!")
return inner
fn = outer(fn)
fn()
# 打印结果:
# 这是最初的函数!
# 打印一行给你看看,这就是添加的新功能!
分析:
函数的执行顺序:
1.python 程序是从上往下执行的,程序先读第1,4行程序(不执行),
2.执行第9行代码,但是先从右侧开始执行,
3.执行outer(fn),程序跳转到第4行,读入inner函数,跳转到8行,执行return,将inner地址返回
4.返回的inner地址被fn接收,执行最后一行代码
5.执行的fn()相当于执行inner()函数,也就是执行inner函数的函数体,由func()和其下一行组成
6.其中第6行就是原先的函数 fn(),下一行就是增加的功能
7.整个程序就实现了在原有基础函数不改变的情况下,增加了新的功能
# 外层函数
def outer(f):
def inner():
f()
print("这里是新增加的功能!11")
return inner
def wrap(f):
def inner():
f()
print("这里也是新增加的功能!22")
return inner
@wrap
@outer
def fn():
print("这里是本来的功能!")
fn()
# 执行结果:
# 这里是本来的功能!
# 这里是新增加的功能!11
# 这里也是新增加的功能!22
分析:
多个装饰器同时装饰同一个函数,可以理解成 俄罗斯套娃 的形式,
谁离被装饰的函数越近,谁就先执行装饰任务
"""
# 有参数有返回值的函数被装饰
"""
def check_user(fn):
def inner(usr, pwd): # inner == login
# 在原功能的基础上添加新功能
# 如果名字长度超过 3 并且 名字是纯字母数字
if not (len(usr) >= 3 and usr.isalpha()):
print("账号验证失败!")
return False
# 满足条件情况下,执行原有的功能
result = fn(usr, pwd)
return result
return inner
@check_user # login = check_user(login)
def login(usr,pwd):
if usr == 'abc' and pwd =='123qwe':
print('登录成功!')
return True
print('登录失败!')
return False
login('abc', '123qwe') # 应该先看最下面这一条执行的函数
总结:
1.login有参数,所以inner与fn都有相同的参数
2.login有返回值,所以inner与fn都有返回值
"""
# 装饰器最终写法
"""
def wrap(fn):
def inner(*args, **kwargs):
print('前增功能')
result = fn(*args, **kwargs)
print('后增功能')
return result
return inner
@wrap
def fn1():
print('fn1的原有功能')
@wrap
def fn2(a, b):
print('fn2的原有功能')
@wrap
def fn3():
print('fn3的原有功能')
return True
@wrap
def fn4(a, *, x):
print('fn4的原有功能')
return True
fn1()
fn2(10, 20)
fn3()
fn4(10, x=20)
"""
# 带参装饰器
"""
def outer(input_color):
def wrap(fn):
if input_color == 'red':
info = '\033[36;42m new action \033[0m'
else:
info = 'yellow:new action'
def inner(*args, **kwargs):
pass
result = fn(*args, **kwargs)
print(info)
return result
return inner
return wrap # outer(color) => wrap
color = input('color: ')
@outer(color) # @outer(color) ==> @wrap # func => inner
def func():
print('func run')
func()
"""
# 案例
# 登录认证功能
"""
is_login = False
def login():
usr = input('usr: ')
if not (len(usr) >= 3 and usr.isalpha()):
print('账号验证失败!')
return False
pwd = input('pwd: ')
if usr == 'abc' and pwd == '123qwe':
print('登录成功!')
is_login = True
else:
print('登录失败!')
is_login = False
# 完成一个登录状态验证的装饰器
def check_login(fn):
def inner(*args,**kwargs):
if is_login != True:
print("你未登录!")
login()
# 执行被装饰的函数功能
result = fn(*args,**kwargs)
return result
return inner
# 查看个人主页功能
@check_login
def home():
print('个人主页')
# 销售功能
@check_login
def sell():
print('清仓大甩卖!')
# 测试函数
home()