1、函数对象
函数名就是存放了函数的内存地址,存放了内存地址的变量都是对象,即 函数名 就是 函数对象
函数对象的应用场景
- 可以直接被引用
- 可以当作函数参数传递
- 可以作为函数的返回值
- 可以作为容器类型的元素
功能体
def add(n1, n2):
return n1 + n2
def low(n1, n2):
return n1 - n2
def jump(n1, n2):
return n1 * n2
完成功能
def computed(n1, n2, fn): # fn = add|low|jump
res = fn(n1, n2) # 调用具体的功能
return res
功能对应关系
method_map = { # 指令与函数对象的对应关系
'1': add,
'2': low,
'3': jump
}
获取功能
def get_method(cmd):
if cmd in method_map:
return method_map[cmd] # 返回 add|low|jump
return add # 当指令错误,add作为默认功能
while True:
cmd = input('cmd: ')
res = get_method(cmd)(10, 20) # 根据指令获取功能并调用得到结果
print(res)
2、函数的嵌套调用
函数的嵌套调用:在一个函数内部调用另一个函数
# 求两个数最大值
def max_two(n1, n2):
if n1 > n2:
return n1
return n2
# 求三个数最大值
def max_three(n1, n2, n3):
max = max_two(n1, n2)
return max_two(max, n3)
# 求四个数最大值
def max_four(n1, n2, n3, n4):
max = max_three(n1, n2, n3)
return max_two(max, n4)
print(max_four(20, 50, 30, 50))
3、名称空间
名称空间:存放名字与内存空间地址对应关系的容器
作用:解决由于名字有限,导致名字重复发送冲突的问题 - 内置全局局部可以同时使用一个名字存放不同地址
三种名称空间
Built-in:内置名称空间;系统级,一个;随解释器执行而产生,解释器停止而销毁
Global:全局名称空间;文件级,多个;随所属文件加载而产生,文件运行完毕而销毁
Local:局部名称空间;函数级,多个;随所属函数执行而产生,函数执行完毕而销毁
加载顺序:Built-in > Global > Local
-- 采用堆栈存储数据的方式(压栈),导致内置最后被访问
案例:
# part1
'''
x = 100
def fn():
a = 10
fn()
# 没有缩进直接使用, 和在其他函数中,都只能使用x,不能使用函数内部的a
def func():
print(x)
func()
# 问题点:什么导致变量的访问权限
'''
# part2
# 名称空间:存放变量名与栈区内存地址的对应关系
print(len('123'))
len = 10
print(len)
del len
print(len('abc'))
print(len)
len = 200
print(type(len))
def fn():
len = 2000
print(len)
fn()
print(len)
4、函数的嵌套定义
函数的嵌套定义:在函数内部定义函数
诞生的理由:一个函数想使用另一个函数内部的变量,可以定义在其内部
def func():
a = 10
def fn():
print(a)
return fn
new_fn = func()
new_fn()
两个与函数有关的关键字:global nonlocal
# global:统一局部与全局的变量名
num = 10
def outer():
# global num
# num = 100
def inner():
global num
num = 1000
# nonlcal: 统一局部与嵌套局部的变量名
def outer():
num = 100
def inner():
nonlocal num
num = 1000
5、作用域
# 作用域:名字起作用的范围
# 作用:解决同名字可以共存问题 - 不同作用域相同名字的值都能在其作用域范围下进行使用
'''
四种作用域: LEGB
Built-in:内置作用域 - 所有文件所有地方都可以被访问
Global:全局作用域 - 在当前文件的所有位置
Enclosing:嵌套作用域 - 自身内部与内部的子函数
Local:局部作用域 - 只有自身内部
'''
# 加载顺序:Built-in > Global > Enclosing > Local
# 访问(查找)顺序:报错 < Built-in < Global < Enclosing < Local
# 作用范围:Built-in > Global > Enclosing > Local
6、闭包
闭包:定义在函数内部的函数,这个内部的函数就是闭包
应用场景:
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()
7、装饰器
装饰器:装饰器就是闭包的一个应用场景
-- 外层函数与内存函数形成的闭包结构的一种综合使用
重点:开放封闭原则
开放:拓展功能的点是开放的 - 可以为之前的函数添加新功能
封闭: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
装饰器案例
# 为登录功能添加账号检验功能:必须是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):
# outer与inner之间要使用外部数据
# 可以解决的方案路径,给outer添加参数,但是outer的参数是固定一个,就是被装饰的函数
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
# 所以只能使用函数的闭包,通过外层函数给内存函数传递参数的方式
def wrap(*arg, **kwargs):
def outer(func):
# 就可以使用wrap中的*arg, **kwargs,就是要使用的外部数据
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
return outer
a = 10
b = 20
@wrap(a, b) # @wrap(10, 20) => @outer => fn = outer(fn) => fn = inner
def fn():
pass
wraps修改函数文档注释
# 为什么要出现该语法
from functools import wraps
def outer(func):
@wraps(func)
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
def fn():
'''
fn的文档注释
'''
print(fn.__doc__) # fn本质是inner,使用打印fn.__doc__本质是inner函数的文档注释
# 形参假象:让打印fn.__doc__显示的效果是fn自己的
文档更新时间: 2019-04-22 10:53 作者:李延召