这一部分在于理解函数的运行,装饰器是为不动用已完成函数内部的东西而在其前后进行操作,很像是变脸,赋值的变化很有意思.
一函数的运
这一部分是对闭包和装饰器的初级了解,理解了更好进行下边的操作:
def func(): print("呵呵") print(func) def func(): print("呵呵") print(func) a = func # 把函数当成⼀一个变量量赋值给另⼀一个变量量 a() # 函数调⽤用 func() def func1(): print("呵呵") def func2(): print("呵呵") def func3(): print("呵呵") def func4(): print("呵呵") lst = [func1, func2, func3] for i in lst: i() def func(): print("吃了了么") def func2(fn): print("我是func2") fn() # 执⾏行行传递过来的fn print("我是func2") func2(func) # 把函数func当成参数传递给func2的参数fn. def func_1(): print("这⾥里里是函数1") def func_2(): print("这⾥里里是函数2") print("这⾥里里是函数1") return func_2 fn = func_1() # 执⾏行行函数1. 函数1返回的是函数2, 这时fn指向的就是上⾯面函数2 fn() # 执⾏行行上⾯面返回的函数
函数名是⼀一个变量量, 但它是⼀一个特殊的变量量, 与括号配合可以执⾏行行函数的变量量.
1函数名的内存地址
2函数名可以赋值给其他变量
3函数名可以当做容量
4函数名可以当做函数的参数
5函数名可以作为函数的返回值
2闭包
闭包中在不改变最外层的值时,我们可以调用赋值相同的数值:
使用global 和nonlocal的会比较多,
什什么是闭包? 闭包就是内层函数, 对外层函数(非全局)的变量量的引⽤用. 叫闭包
ef func1(): name = "alex" def func2(): print(name) # 闭包 func2() func1() 结果: alex
我们可以使⽤用__closure__来检测函数是否是闭包. 使⽤用函数名.__closure__返回cell就是
闭包. 返回None就不是闭包
问题, 如何在函数外边调⽤用内部函数呢? def outer(): name = "alex" # 内部函数 def inner(): print(name) return inner fn = outer() # 访问外部函数, 获取到内部函数的函数地址 fn() # 访问内部函数 那如果多层嵌套呢? 很简单, 只需要⼀一层⼀一层的往外层返回就⾏行行了了 def func1(): def func2(): def func3(): print("嘿嘿") return func3 return func2 func1()()()
爬虫
from urllib.request import urlopen def but(): content = urlopen("http://www.xiaohua100.cn/index.html").read() def get_content(): return content return get_content fn = but() # 这个时候就开始加载校花100的内容 # 后⾯面需要⽤用到这⾥里里⾯面的内容就不不需要在执⾏行行⾮非常耗时的⽹网络连接操作了了 content = fn() # 获取内容 print(content) content2 = fn() # 重新获取内容 print(content2) 综上, 闭包的作⽤用就是让⼀一个变量量能够常驻内存. 供后⾯面的程序使⽤用.
三装饰器的初识 初识者要谨记模板 如果要跳出需要在全局增加一个start = False 跳出时加star = Ture
在说装饰器之前啊. 我们先说⼀一个软件设计的原则: 开闭原则, ⼜又被成为开放封闭原则,
你的代码对功能的扩展是开放的, 你的程序对修改源代码是封闭的. 这样的软件设计思路路可以
更更好的维护和开发.
开放: 对功能扩展开放
封闭: 对修改代码封闭
def wrapper(func): def inner(*args, **kwargs): '''在执⾏行行⽬目标函数之前要执⾏行行的内容''' ret = func(*args, **kwargs) '''在执⾏行行⽬目标函数之后要执⾏行行的内容''' return ret return inner # @wrapper 相当于 target_func = wrapper(target_func) 语法糖 @wrapper def target_func(): print("我是⽬目标函数") # 调⽤用⽬目标函数 target_func()
现在问题⼜又来了了. 你这个函数写好了了. 但是由于你添加了了功能. 重新创建了了个函数. 在这之
前访问过这个函数的⼈人就必须要修改代码来访问新的函数water() 这也要修改代码. 这个也不
好. 依然违背开闭原则. ⽽而且. 如果你这个函数被⼤大量量的⼈人访问过. 你让他们所有⼈人都去改. 那
你就要倒霉了了. 不⼲干死你就⻅见⿁鬼了了.
那怎么办才能既不修改原代码, ⼜又能添加新功能呢? 这个时候我们就需要⼀一个装饰器了了. 装
饰器的作⽤用就是在不修改原有代码的基础上, 给函数扩展功能.
def create_people(): # print("浇⽔水") # 添加了了个浇⽔水功能, 不不符合开闭原则了了 print("⼥女女娲很厉害. 捏个泥泥⼈人吹⼝口⽓气就成了了⼈人了了") def warter(fn): def inner(): print("浇浇⽔水") fn() print("施肥") return inner # # create_people() # 这个就不不⾏行行了了. # warter() # 访问浇⽔水就好了了 func = warter(create_people) func() # 有⼈人问了了. 下游访问的不不依然是func么, 不不还是要改么? create_people = warter(create_people) create_people() # 这回就好了了吧
1. ⾸首先访问warter(create_people).
2. 把你的⽬目标函数传递给warter的形参fn. 那么后⾯面如果执⾏行行了了fn意味着执⾏行行了了你的⽬目
标函数create_people
3. warter()执⾏行行就⼀一句句话. 返回inner函数. 这个时候. 程序认为warter()函数执⾏行行完. 那么
前⾯面的create_people函数名被重新覆盖成inner函数
4. 执⾏行行create_people函数. 实际上执⾏行行的是inner函数. ⽽而inner中访问的恰恰使我们最开
始传递进去的原始的create_people函数
结论: 我们使⽤用warter函数把create_people给包装了了⼀一下. 在不修改create_people的前提下.
完成了了对create_people函数的功能添加
我们发现, 代码运⾏行行的结果是⼀一样的. 所谓的语法糖语法: @装饰器 类似的操作在我们⽣生活中还有很多. 比⽅方说. 约⼀一约. # 2--> 现在啊, 这个⾏行行情⽐比较不不好, 什什么⽜牛⻤鬼蛇神都出来了了. # 那怎么办呢? 问问⾦金金⽼老老板. ⾦金金⽼老老板在前⾯面给⼤大家带路路 # 这时候我们就需要在约之前啊. 先问问⾦金金⽼老老板了了. 所以也要给函数添加⼀一个功能, 这⾥里里依然可以使 ⽤用装饰器器 def wen_jin(fn): def inner(): print("问问⾦金金⽼老老板, ⾏行行情怎么样, 质量量好不不好") fn() print("⺾艹, ⾦金金⽼老老板骗我") return inner @wen_jin def yue(): # 1--> 约⼀一约函数 print("约⼀一约") yue()
这样就够了了么? 如果我的yue()改成两个参数呢? 你是不是还要改inner. 对了了. ⽤用*args和 **kwargs来搞定多个参数的问题 def wen_jin(fn): def inner(*args, **kwargs): # 接收任意参数 print("问问⾦金金⽼老老板, ⾏行行情怎么样, 质量量好不不好") fn(*args, **kwargs) # 把接收到的内容打散再传递给⽬目标函数 print("⺾艹, ⾦金金⽼老老板骗我") return inner @wen_jin def yue(name): print("约⼀一约", name) yue("wusir") 搞定. 这时 wen_jin()函数就是⼀一个可以处理理带参数的函数的装饰器 光有参数还不够. 返回值呢? def wen_jin(fn): def inner(*args, **kwargs): print("问问⾦金金⽼老老板, ⾏行行情怎么样, 质量量好不不好") ret = fn(*args, **kwargs) # 执⾏行行⽬目标函数. 获取⽬目标函数的返回值 print("⺾艹, ⾦金金⽼老老板骗我") return ret # 把返回值返回给调⽤用者 return inner @wen_jin def yue(name): print("约⼀一约", name) return "⼩小萝莉" # 函数正常返回 r = yue("wusir") # 这⾥里里接收到的返回值是inner返回的. inner的返回值是⽬目标函数的返回 值 print(r)
2,下面代码打印的结果分别是_________,________,________.
def extendList(val,list=[]):
list.append(val)
return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')
print('list1=%s'%list1)
print('list2=%s'%list2
print('list3=%s'%list3)
分析下这道题,当函数在函数名后括号等于list=[]或者{}时,我们认为凡是没有在输入值时创建列表和字典时,都要传进这个列表或字典,如果在赋值时创建了,我们认为它创建了单独的字典或者列表,所以list1和list3在默认列表中而list2在自己的列表中.