python函数2_闭包和装饰器
变量的范围
作用域
- 优先级:L > E > G > B
- L,local,当前函数中的变量
- E,encloseing,父函数中的变量
- G,Global,全局变量
- B,built-in,内置函数
局部/全局
- 局部变量
- 在函数内部声明的变量
- 在函数体外部无法获取
- 全局变量
- 在函数外部声明的变量
- 所有函数都可以访问
在函数内,局部变量和全局变量同名,优先使用局部变量
name = '月月'
def fun2():
name = '小月月'
name += '会弹吉他'
print(name)
fun2()
小月月会弹吉他
当在函数体内,尝试更改全局变量会报错
name = '月月'
def fun2():
print(name)
name += '会弹吉他'
fun2()
当需要在函数体内修改全局变量时,需要加global
只是获取不需要加
name = '月月'
def fun2():
global name
name += '会弹吉他'
print(name)
fun2()
print(name)
月月会弹吉他
月月会弹吉他
当在函数中要修改的全局变量是可变类型的,如列表,则不需要添加global关键字
list1 = ['python','php','go']
def fun2():
list1.append('java')
fun2()
print(list1)
['python', 'php', 'go', 'java']
内部函数
可以访问外部函数的变量
a = 10
def func1():
b = 20
def func2():
print(a,b)
func2()
func1()
10 20
内部函数可以修改外部函数的可变类型的变量比如:list
list1 = ['python','php','go']
def func1():
list2 = ['html','css']
def func2():
list1.append('java')
list2.append('javascript')
print(list1,list2,sep='\n')
func2()
func1()
['python', 'php', 'go', 'java']
['html', 'css', 'javascript']
内部函数修改全局的不可变变量时,需要在内部函数声明global 变量名
a = 10
def func1():
b = 20
def func2():
global a
a += b
print(a,b)
func2()
func1()
内部函数修改外部函数的不可变变量时,需要在内部函数中声明,nonlocal 变量名
a = 10
def func1():
b = 20
def func2():
nonlocal b
b += a
print(a,b)
func2()
func1()
locals(),可以看到当前函数中声明的变量有哪些,以字典的形式输出
a = 10
def func1():
b = 20
def func2():
nonlocal b
b += a
print(locals())
func2()
print(locals())
func1()
{'b': 30}
{'func2': <function func1.<locals>.func2 at 0x000001BF232F4730>, 'b': 30}
globals(),查看全局变量有那些,以字典的形式输出(会有一些系统中的键值对)
a = 10
def func1():
b = 20
def func2():
nonlocal b
b += a
print(globals())
func2()
func1()
闭包
概念
闭包的条件
- 外部函数中定义了内部函数
- 外部函数是有返回值
- 返回的值是: 内部函数名
- 内部函数引用了外部函数的变量
闭包的优缺点
- 闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
- 闭包使代码变得简洁,便于阅读代码
def func1():
a = 10
def func2():
b = 20
print(a,b)
return func2
new1 = func1()
new1()
10 20
def func(a,b):
c = 10
def inner_func():
s = a + b + c
print(s)
return inner_func
ifunc = func(1,2)
ifunc()
13
闭包的简单应用
保存返回闭包时外层函数变量的状态
def func(a,b):
c = 10
def inner_func():
s = a + b + c
print(s)
return inner_func
ifunc = func(1,2)
ifunc1 = func(3,4)
ifunc2 = func(5,6)
ifunc()
ifunc1()
ifunc2()
13
17
21
计数器
def generate_count():
container = [0]
def add_c():
container[0] = container[0] + 1
print('当前是第{}次访问'.format(container[0]))
return add_c
counter = generate_count()
counter()
counter()
counter()
当前是第1次访问
当前是第2次访问
当前是第3次访问
闭包同级别访问
def func():
a = 10
def inner_func1():
b = 90
print(a+b)
def inner_func2():
inner_func1()
return 'hello'
return inner_func2
f1 = func()
f2 = f1()
print(f2)
100
hello
装饰器
装饰器函数中,被装饰函数函数是作为参数出现的
要有闭包的特点
定义使用装饰器
定义一个装饰器
def decorate(func):
def wrapper():
func()
print('--->刷漆')
print('--->铺地板')
print('--->装门')
return wrapper
使用装饰器
@decorate
def house():
print('我还是毛坯房')
调用函数
house()
我还是毛坯房
--->刷漆
--->铺地板
--->装门
当遇到装饰器,会自动完成
- 当解释器读取到@decorate时,将house()函数作为被装饰函数
- 将被装饰函数作为参数传给装饰器decorate
- 执行decorate函数
- 将返回值又赋值给house
所以调用house()时,其实调用的是wrapper()
import time
def decorate(f):
def wrapper():
print('正在校验中')
time.sleep(2)
print('校验完毕')
f()
return wrapper
@decorate
def f1():
print('--f1--')
@decorate
def f2():
print('--f2--')
f1()
f2()
正在校验中
校验完毕
--f1--
正在校验中
校验完毕
--f2--
函数的参数
import time
def decorate(f):
def wrapper(*args,**args2):
print('正在校验中')
time.sleep(2)
print('校验完毕')
f(*args,**args2)
return wrapper
name1 = 'tom'
list1 = ['tom','json','peop']
kv1 = {'01':'tom','02':'json','03':'peop'}
@decorate
def f1(n1):
print('--f1--',n1)
@decorate
def f2(n1,l1):
print('--f2--',n1,l1)
@decorate
def f3(n1,l1,k1):
print('--f3--',n1,l1,k1)
f1(name1)
f2(name1,list1)
f3(name1,list1,kv1)
正在校验中
校验完毕
--f1-- tom
正在校验中
校验完毕
--f2-- tom ['tom', 'json', 'peop']
正在校验中
校验完毕
--f3-- tom ['tom', 'json', 'peop'] {'01': 'tom', '02': 'json', '03': 'peop'}
多层装饰器
def decorate1(func):
print('--->one')
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print('刷漆')
return wrapper
def decorate2(func):
print('--->two')
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print('铺地板')
return wrapper
@decorate1
@decorate2
def house():
print('我是毛坯房')
house()
--->two
--->one
我是毛坯房
铺地板
刷漆
-
当存在多个装饰器时,先执行距离被装饰函数近的装饰器
- 先到@decorate2装饰器中,执行打印two,加载wrapper函数,并将返回值又赋值给house
- 然后再到@decorate1装饰器中,执行打印one,加载wrapper函数,并将返回值又赋值给house
-
当调用house()时
- 此时house()为@decorate1中的wrapper()函数
- 当执行到func()会跳转到第一层@decorate2中的wrapper()函数
- 此函数中的func()函数执行时,会执行house()函数中的内容,打印毛坯房
- 接着打印铺地板
- 然后回到跳转时的状态,再打印刷漆
装饰器的参数
当装饰器需要带参数时,装饰器使的外层需要再嵌套一层
发现下面装饰器的例子中的装饰器,嵌套了三层
可以理解为
- 最外层outer(),负责接收装饰器参数的
- decorate(),负责接收函数的
- 最内层wrapper(),负责接收函数参数的
def outer(n):
def decorate(func):
def wrapper(*args):
func(*args)
print('铺{}块地砖'.format(n))
return wrapper
return decorate
n1 = 10
n2 = 1200
times = '2020.01.01'
@outer(n1)
def house(time):
print('我{}拿到房子的钥匙,是毛坯房'.format(time))
@outer(n2)
def street():
print('新修街道:黑泉路')
house(times)
street()
我2020.01.01拿到房子的钥匙,是毛坯房
铺10块地砖
新修街道:黑泉路
铺1200块地砖
登录验证
import time
islogin = False
def login():
username = input('请输入用户名: ')
password = input('输入密码: ')
if username == 'admin' and password == '123456':
return True
else:
return False
def login_required(func):
def wrapper(*args,**kwargs):
global islogin
print('----付款----')
while True:
if islogin:
func(*args,**kwargs)
break
else:
print('用户没有登录,不能付款')
islogin = login()
return wrapper
@login_required
def pay(money):
print('正在付款,付款金额是:{}元'.format(money))
print('付款中.')
time.sleep(1)
print('付款完成!')
pay(10)
----付款----
用户没有登录,不能付款
请输入用户名: admin
输入密码: 123
用户没有登录,不能付款
请输入用户名: admin
输入密码: 123456
正在付款,付款金额是:10元
付款中.
付款完成!
匿名函数
匿名函数
作用:简化函数定义
格式
lambda 参数:返回的结果
s1 = lambda x,y : x*y
result = s1(2,5)
print(result)
10
匿名函数作为参数
def func(x,y,f):
s = f(x,y)
print(s)
func(2,3,lambda a,b : a*b)
6
匿名和内置配合使用
max()
min()最小值也是相同用法
查找列表中最大值
list1 = [1,4,8,2,4,1]
a = max(list1)
print(a)
8
查找列表中a是最大值的字典
list2 = ({'a':10,'b':20},{'a':15,'b':20},{'a':7,'b':20})
a = max(list2,key=lambda x:x['a'])
print(a)
{'a': 15, 'b': 20}
map()
将列表中的每一个元素加2
list1 = [1,4,8,2,4,1]
for index,i in enumerate(list1):
list1[index]=i+2
print(list1)
[3, 6, 10, 4, 6, 3]
list1 = [1,4,8,2,4,1]
result = map(lambda x:x+2,list1)
print(list(result))
[3, 6, 10, 4, 6, 3]
将列表中的值,奇数+1.
list1 = [1,4,8,2,4,1,5,7]
result = map(lambda x:x if x%2==0 else x+1,list1)
print(list(result))
[2, 4, 8, 2, 4, 2, 6, 8]
list1 = [1,4,8,2,4,1,5,7]
for index,i in enumerate(list1):
if i%2 != 0:
list1[index] = i+1
print(list1)
[2, 4, 8, 2, 4, 2, 6, 8]
reduce()
对列表中的元素进行加减乘除运算的函数
使用时,需要导入
from functools import reduce
list1 = [1,4,5,2,3,65,1,4,7,5]
result = reduce(lambda x,y : x+y,list1)
print(result)
97
执行过程,
- 先取1,4,进行相加,
- 然后将结果和再次取来的5进行相加,以此类推
设置初始值
当列表中只有1个元素时,因为要获取两个值,
但是只能获取一个值,会将另一个值看作是0或者null
list1 = [10]
result1 = reduce(lambda x,y : x-y,list1)
result2 = reduce(lambda x,y : x-y,list1,100)
print(result1,result2)
10 90
filter()
查找列表中小于10的元素
list1 = [12,5,7,5,4,13,100,10]
result = filter(lambda x : x>10, list1)
print(list(result))
[12, 13, 100]
list1 = [12,5,7,5,4,13,100,10]
result = []
for i in list1:
if i > 10:
result.append(i)
print(result)
[12, 13, 100]
找出所有年龄大于20岁的学生
students = [
{'name':'tom','age':25},
{'name':'jack','age':19},
{'name':'lily','age':27}
]
result = filter(lambda x : x['age']>20,students)
print(list(result))
[{'name': 'tom', 'age': 25}, {'name': 'lily', 'age': 27}]
sorted()
按照年龄排序
students = [
{'name':'tom','age':25},
{'name':'jack','age':19},
{'name':'lily','age':27}
]
result = sorted(students,key=lambda x : x['age'])
print(result)
result2 = sorted(students,key=lambda x : x['age'],reverse=True)
print(result2)
[{'name': 'jack', 'age': 19}, {'name': 'tom', 'age': 25}, {'name': 'lily', 'age': 27}]
[{'name': 'lily', 'age': 27}, {'name': 'tom', 'age': 25}, {'name': 'jack', 'age': 19}]
递归函数
函数自己调用自己
- 递归函数一定要设置终点
- 通常都会有一个入口
def f1(n):
if n>0:
print(n)
f1(n-1)
else:
print(n)
f1(5)
5
4
3
2
1
0

浙公网安备 33010602011771号