关于问题的注意事项
nonlocal 的问题
nonlocal的变量范围问题,可以获取上层函数的变量,如果上层函数没有这个变量,那么会到上上层找,但不会到全局找.
示例如下:
def fun():
a = 1
def fun2():
a = 2
def fun3():
nonlocal a
print(a)
fun3()
fun2()
fun()
"""
运行结果
不注释a=2时话是2,注释后是1
"""
关于全局作用域和局部作用域的问题
示例:
def fun():
a = 1
def fun2():
a += 1
print(a)
fun2()
fun()
"""
这里会报错的,因为如果在局部一但赋值操作,python解释器就会认为是局部变量,局部变量的话,需要先赋值
"""
关于dic增加的j时dic.setdefault(“key”,“value”)
这个dic.setdefault(“key”,“value”)有增另键值对的功能 ,这里需要注意到的是,这个会有返回.返回的值是value的值.
由于setdefault这个值,当字典中存在这个key时,这次的增加是无效的,但是这个会返回现在字典中这个key的value值.如果不存在key会返回setdefault设置的value值.
示例如下:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
dic = {}
dic.setdefault("key","value")
print(dic)
"""
这个是增加字典的键值
"""
关于 ** kwargs 这个值,不能传入 ** {3:4}这样的值,因为传参相当于变量,变量不能接受纯数字当变量的.
示例:
def func(**kwargs):
print(kwargs)
def(**{"a":2,"b":3},**{3:4})
关于函数默认赋值的深坑
def func(a,lst = []):
lst.append(a)
return lst
如下问题:
lst1 = func("10")
lst2 = func("20",[])
lst3 = func("30")
最后print(lst1,lst2,lst3)
下面是运行结果
['10', '30'] ['20'] ['10', '30']
原因是当形参传入可变值时,python解释器会分配一个对像,这个对像是不变的,当多次调这个函数时,指向的是同一个地址.所以函数默认传参应该尽量传入可hash的,也就是不可变类型的.
上面是补充,补充完毕
本节主要内容: 1. 函数名的运⽤, 第⼀类对象 2. 闭包 3. 装饰器初识
1. 函数名的运⽤, 第⼀类对象
函数名是一个变量,但它是一个特殊的变量加个()是可以执行的变量
函数名有 以下特性:
1)函数名是一个内存地址,
示例:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def fun():
print(100)
print(fun)
上面的代码是打印函数的内存地址.
2)函数名可以赋值给其他变量
示例:
示例是把函数名赋值给b,然后b执行了这个函数
def fun():
print(100)
b = fun
b()
3)函数名可以当做容器类的元素
函数名可以当做其他容器类的无素,容器类如,列表,字典等
示例:
def fun1():
print("1")
def fun2():
print("2")
def fun3():
print("3")
lst = [fun1,fun2,fun3]
for e in lst:
print(e)
"""
变量名只是内存地址,循环调用的话,只是显示了内存地址
"""
4).函数名可以当做函数的参数
示例:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def fun():
print("呵呵")
def fun1(fn):
fn()
fun1(fun)
5). 函数名可以作为函数的返回值
示例:
def fun():
def inner():
print("123")
return inner
f = fun()
f()
"""
函数的返回
"""
2. 闭包
什么是闭包? 闭包就是内层函数, 对外层函数(非全局)的变量的引⽤. 叫闭包
示例:
def fun():
a = 1
def inner():
print(a)
inner()
fun()
可以通过__closure__来查看内层函数是否闭包 __ closure__ 返回none表示不是闭包,返回cell是闭包
如何在函数外部调用闭包,下面是示例
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def fun():
a = 1
def inner():
print(a)
inner()
return inner
f = fun()
print(f.__closure__)
这里会涉及到函数的多层嵌套,如下
def func1():
def func2():
def func3():
print("嘿嘿")
return func3
return func2
func1()()()
由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函 数访问的时间和时机就不⼀定了, 因为在外部, 我可以选择在任意的时间去访问内部函数.
这 个时候. 想⼀想. 我们之前说过, 如果⼀个函数执⾏完毕. 则这个函数中的变量以及局部命名 空间中的内容都将会被销毁. 在闭包中. 如果变量被销毁了. 那内部函数将不能正常执⾏.
所 以. python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡. 将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻. 这样做 有什么好处呢? 非常⼤的好处. 我们来看⼀个关于爬⾍的代码:
3. 装饰器初识
装饰器的作⽤就是在不修改原有代码的基础上, 给函数扩展功能.
示例:
如果现在有函数:
def create_people():
print("⼥娲很厉害. 捏个泥⼈吹⼝⽓就成了⼈了")
想要在不修改这个函数调用的基础上实现增加功能.这个可以采用下面的方法
def wrapper(fn):
def inner():
#开始增加的功能
fn()
#结束要增加的功能
return inner
create_people = wrapper(create_people)
这边来描述一下装饰器执行的原理
1.先写好装饰器函数,
2.调用装饰器,传入函数名,
3,把原有的函数改名
4.调用原有的函数名,
5.实际上是调用wrapper(func)()
6.也就是装饰器的内置函数
结论: 我们使⽤warter函数把create_people给包装了⼀下. 在不修改create_people的前提下. 完成了对create_people函数的功能添加
下面是语法糖格式
示例:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def wrapper(fn):
def inner():
#开始增加的功能
print("夏天来了")
fn()
print("冬天来了")
return inner
@wrapper
def create_people():
print("⼥娲很厉害. 捏个泥⼈吹⼝⽓就成了⼈了")
create_people()
下面是装饰器完整模型代码,
def wrapper(fn):
def inner(*args,**kwargs):
#前面要加的代码
ret = fn(*args,**kwargs)
#后面要加的代码
return ret
return inner
@wrapper
示例
def wrapper(fn):
def inner(*args,**kwargs):
#前面执行的代码
ret = fn(*args,**kwargs)
#后面执行的代码
return ret
return inner
@wrapper