Python函数 - 06函数高级
一、函数嵌套
在函数里面还可以定义函数,可以嵌套多层,执行需要被调用
def outer():
a = 100
def inner():
b = 200
print('内部函数inner')
print(a)
print(inner)
outer()
'''
100
<function outer.<locals>.inner at 0x0000001552A0B310>
'''
locals() 查看函数中的局部变量
def outer():
a = 100
def inner():
b = 200
print('内部函数inner')
result = locals() # locals()表示查看函数中的局部变量,以字典形式返回
print(result)
outer() # {'a': 100, 'inner': <function outer.<locals>.inner at 0x0000000DC2DCB430>}
def outer2():
a = 100
def inner2():
b = 200
b += a # 内部函数可以直接使用外部函数的变量
print('内部函数inner2, a =', a)
print('内部函数inner2, b =', b)
print(a)
inner2()
outer2()
# 100
# 内部函数inner2, a = 100
# 内部函数inner2, b = 300
内部函数对外部函数的变量进行修改、计算
def outer2():
a = 100
def inner2():
b = 200
# b += a 内部函数可以直接使用外部函数的变量
nonlocal a
a += b
print('内部函数inner2, a =', a)
print(a)
inner2()
outer2()
# 100
# 内部函数inner2, a = 300
全局变量
a = 100
def outer3():
a = 200
def inner3():
a = 300
print('内部函数inner3, a =',a)
a -= 50
print('函数outer3, a =',a)
inner3()
outer3()
print('变量, a =',a)
# 函数outer3, a = 200
# 内部函数inner3, a = 300
# 变量, a = 100
a = 100
def outer4():
a = 200
def inner4():
# a = 300
global a
a -= 50
print('内部函数inner4,a =', a)
print(a)
inner4()
outer4()
print(a)
# SyntaxError: name 'a' is assigned to before global declaration
# 将 a = 300 注释掉
# 200
# 内部函数inner4,a = 50
# 50
# 内层函数 --> 外层函数 --> 全局变量 --> 系统 builtins
a = 100
def outer4():
a = 200
def inner4():
nonlocal a
a -= 50
print('内部函数inner4,a =', a)
print(a) # 200
inner4()
outer4() # 内部函数inner4,a = 150
print(a) # 100
二、闭包
def outer5(n):
a = 10
def inner5():
b = a + n
print('内部函数inner5, b =', b)
return inner5
r = outer5(5)
print(r) # <function outer5.<locals>.inner5 at 0x000000A11196B670>
r() # 内部函数inner5, b = 15
函数inner5是函数outer5的内嵌函数,并且inner5函数是outer5函数的返回值。
内嵌函数inner5引用到外层函数中的局部变量n, 每次调用outer5函数都将生成并保存一个新的局部变量n, 这里outer5函数返回的就是闭包。
在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行了引用,那么内部函数就被认为是闭包(closure)。
三、 装饰器
定义一个变量指向函数
def foo():
print('foo')
def bar():
print('bar')
foo = bar
foo() # bar
函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过函数名() 调用,
如果 函数名 = xxx 被修改了,那么当执行函数名()时,调用的就不是之前的那个函数了。
3.1 装饰器: 遵循开放封闭原则,再不改变原函数的情况下,扩展了函数功能。
使用场景: 引入日志、 函数执行时间统计、 执行函数前预备处理、 执行函数后清理功能、 权限校验等场景、 缓存
# 定义,格式
def aaa(func): def xxx(参数,...): ... func() ... return yyy return xxx @aaa def zzz(): pass
def decorator(func):
def wrapper():
func()
print('刷漆')
print('铺地板')
return wrapper
@decorator # house = decorator(house) -> func=house -> house=wrapper
def house():
print('毛坯房....')
house()
装饰器执行过程:
def outer_checker(time):
print('----------->1')
def check_time(action):
print('----------->2')
def do_action():
print('----------->3')
if time < 22:
return action()
else:
return '没有权限'
print('----------->4')
return do_action
print('------------>5')
return check_time
@outer_checker(21)
def play_game():
print('----------->6')
return '玩游戏'
print(play_game())
# outer_checker(21)
----------->1
------------>5
----------->2
----------->4
----------->3
----------->6
玩游戏
# outer_checker(23) r=outer_checker(23) r=check_time -> check_time(play_game) -> play_game=do_action
----------->1
------------>5
----------->2
----------->4
----------->3
没有权限
装饰器带普通参数
# 带参数的装饰器
def decorator2(func):
def wrapper(address):
func(address)
print('刷漆')
print('地板')
return wrapper
@decorator2
def house2(address):
print('房子地址在{},是毛坯房'.format(address))
house2('北京')
装饰器带可变参数args, kwargs
def decorator3(func):
def wrapper(*args):
func(*args) # args是一个元祖, func=house3, func(('老郭','北京',80))
print('刷漆')
print('地板')
return wrapper
@decorator3
def house3(name, address, area=40):
print('客户{}房子地址在{},是毛坯房,面积是{}'.format(name, address, area))
house3('老郭', '北京', 80)
def decorator4(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
print(kwargs)
print('刷漆')
print('地板')
return wrapper
@decorator4
def house4(name, address, area=40, price=40, year=2019):
print('客户{}房子地址在{},是毛坯房,面积是{},竣工在{}年,花了{}万元'.format(name, address, area, year,price))
laoguo={'address':'北京', 'area':80}
house4('老郭', **laoguo)
装饰器中的return
def decorator5(func):
def wrapper(*args, **kwargs):
r = func(*args, **kwargs)
print('装修费用为:{}元'.format(r))
print('刷漆')
print('地板')
return 6000
return wrapper
@decorator5
def house5(name, address, area=40, price=40, year=2019):
print('客户{}房子地址在{},是毛坯房,面积是{}'.format(name, address, area))
return 5000
a = house5('老郭', '北京',60,44) # 装修费用为:5000元
print(a) # 6000
四、递归函数
def a():
print('---------aaa-------------')
a()
# a() # RecursionError: maximum recursion depth exceeded while calling a Python object
# 打印 1 - 10
def p_num(i):
if i == 10:
print('10')
else:
print(i)
i += 1
p_num(i)
p_num(1)
# 计算 1+2+...+9+10
def c_num(i):
if i == 10:
return 10
else:
return i + c_num(i + 1)
c = c_num(1)
print(c) # 55
# 阶乘: 1*2*3*4*...*n
def cal(n):
if n == 1 or n == 2:
return n
else:
return n * cal(n - 1)
c = cal(5)
print(c)
五、 匿名函数
用lambda关键字创建小型匿名函数。 这种函数得名于省略了用def声明函数的标准步骤。
Lambda函数的语法只包含一个语句, 格式为: lambda 参数列表: 运算表达式
def test(a):
return a + 1
r = lambda a: a + 1
print(test) # <function test at 0x000000118E099390>
print(r) # <function <lambda> at 0x000000118E088430>
print(r(8)) # 9
六、高阶函数
在Python中, 函数也是一种数据类型。函数对应的数据类型为 function, 可以把它当做数字或字符串来处理。
函数可以接收另一个函数作为参数,也可以把一个函数当做另一个函数的返回值,这种函数的使用方式称为高阶函数。
6.1 函数作为另一个函数的参数
# -- 传统方式
def test():
print('----test---------')
def func(a, f):
print('------>', a)
f()
func(3, test) # ------> 3 \n ----test---------
# -- Lambda表达式
def test1(n, f):
print('------>', n)
r = f(n)
print('------>', r)
test1(9, lambda x: x ** 2)
6.2 Python中使用函数作为参数的内置函数和类
sorted函数: 用来将一个无序列表进行排序, 函数参数的返回值规定按照元素的哪个属性进行排序
m = max(5, 9) print(m) # 9 m = max([2, 4, 56, 8, 88, 33]) print(m) # 88
list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)] m = max(list1, key=lambda x: x[1]) print(m) # ('xi', 99) m = min(list1, key=lambda x: x[1]) print(m) # ('mm', 15) s = sorted(list1, key=lambda x: x[1], reverse=True) print(s) # [('xi', 99), ('jack', 20), ('tom', 19), ('mm', 15)]
filter类: 用来过滤一个列表里符合规定的所有元素,得到的结果是一个迭代器,函数参数的返回值指定元素满足的过滤条件。
map类: 将列表里的每一项数据都执行相同的操作,得到一个迭代器, 函数参数用来指定列表里元素所执行的操作。
reduce函数: 对一个序列进行压缩算法,得到一个值。python3,方法移动到functools模块, 函数参数用来指定按照哪种方式合并。
list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)] # filter的匿名函数要求返回值必须是bool类型,只有bool类型结果为True才是符合过滤条件的
rr = filter(lambda x: x[1] > 20, list1) print(rr) # <filter object at 0x000000516B500430> print(list(rr)) # [('xi', 99)]
# 通过匿名函数指明提取的内容,并对内容进行加工 map = map(lambda x: x[1] + 1, list1) print(map) # <map object at 0x0000003B1B4F03A0> print(list(map)) # [20, 21, 100, 16] print(list1) # 不变
map1 = map(lambda x: x[0].title(), list1) print(list(map1)) # ['Tom', 'Jack', 'Xi', 'Mm']
# 对map迭代器的处理只能一次,处理之后map1 不存在
list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)]
map1 = map(lambda x: x[1], list1)
print(list(map1)) # [19, 20, 99, 15]
print(list(map1)) # []
from functools import reduce
list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)]
map1 = map(lambda x: x[1], list1)
list2 = list(map1)
print(list2) # [19, 20, 99, 15]
red = reduce(lambda x, y: x + y, list2)
print(red) # 153