一、函数嵌套1.函数嵌套调用函数嵌套调用指的是在函数内部又调用了其他的函数。# 求三个数的最大值 def max2(x, y): if x y: return X else: return y def max3(x, y, z): res1 max2(x, y) res2 max2(res1, z) return res2 print(max3(11, 199, 2))2.函数嵌套定义函数的嵌套定义指的是在函数内又定义了其他函数。#示例1 def funcl(): print(from func1) def func2(): print(from func2) print(func2) func2() func1() # print(func2) # 示例2 # 函数在定义阶段不执行函数体内的代码 def f1(): print(f1) def f2(): print(f2) def f3(): print(f3) f3() f2() f1()二、名称空间1.名称空间说明名称空间从字面意思理解是存放名字的地方最开始我们在讲解变量的时候知道定义一个变量就是开辟一块内存空间这个内存空间存放的是变量的值除了变量值之外还有变量名变量名与变量值的绑定关系这个数据要在内存中存储。变量名是名字函数名也是名字名称空间就是存放名字与值的绑定关系的地方。2.名称空间的分类名称空间分为三类1.内置名称空间存放Python解释器自带的名字在解释器启动时就生效解释器关闭则失效。2.全局名称空间文件级别的名字,在执行文件的时候生效在文件结束或者在文件执行期间被删除则失效。有些全局名称空间可能一眼看上去不像是全局名称空间我们只需要记住只要不是内置名称空间和局部名称空间那么就是全局名称空间。3。局部名称空间存放函数内定义的名字(函数的参数以及函数内的名字都存放于局部名称空间)在函数调用时临时生效函数结束则失效。#内置 print(print) print(len) #以下4个都是全局 x 1 #全局 def func(): #func是全局名称空间 name Albert #name是局部名称空间 # del func #我们不需要自己删除 if 10 3: y 2 #全局 while True: z 5 #全局 break #局部 def func1(x): #实参1传给形参x就相当于在函数内被定义 x1故x为局部 # x 1 y 2 # 局部 func1(1)内置名称空间与全局名称空间的结束的生命周期基本上是一致的程序执行结束或者文件关闭(手动强制关闭写python代码的这个文件)内置或全局名称空间生命周期结束。局部名称空间生命周期是从函数调用开始到函数结束即函数生命周期终正。加载顺序内置名称空间-全局名称空间-局部名称空间查找名字局部名称空间-全局名称空间-内置名称空间#加载顺序很好理解查找顺序是以当前位置为起始点 len 0 #我们是为了测试自己写代码千万不能覆盖内置名称空间 def fl(): # len 1 def f2(): # len 2 print(len) # len 3 £2() f1()三、作用域1.全局作用域全局作用域包含的是内置名称空间与全局名称空间的名字它的特点是1.在任何位置都能够访问的到2.该范围内的名字会伴随程序整个生命周期如果在局部使用全局作用域的变量是没有问题的但是如果是在局部修改全局作用域的变量则不能直接修改而要使用 global 关键字才可以修改。global_count 0 def global_check(): print(global_count) #直接使用全局变量 def global_modify(): global global_count #修改前需要先使用global global_count 1 print(global_count) global_check() global_modify()2.局部作用域局部作用域包含的是局部名称空间的名字它的特点是1.只能在函数内使用2.调用函数时生效调用结束失效如果在局部使用的是嵌套在函数内部的局部变量同理可以直接使用而修改需要使用nonlocal关键字。def make_counter(): count 0 def check_counter(): print(count) check_counter() def modify_counter(): nonlocal count count 1 print(count) modify_counter() make_counter()四、函数对象1.函数对象说明函数在Python中是第一类对象这句话可以通俗理解为函数也是一个对象就像是int字符串列表和字典一样都是对象等讲到了面向对象我们就会对这个概念有了进一步理解现在就可以暂时理解为函数对象可以像int或者字符串一样使用。#1函数可以被引用 # int示例 x 1 y x #函数示例 def bar(): print(from bar) f bar f() #2可以当中参数传入 #int示例 x 1 def func(a): print(a) func(x) #函数示例 def bar(): print(from bar) def wrapper(func): func() wrapper(bar) # 3 可以当中函数的返回值 # int 示例 x 1 def foo(): return x res foo() print(res) # 函数示例 def bar() print(from bar) def foo(func) return runc f foo(bar) f() # 4 可以当中容器类型的元素 # int 示例 z 1 l [z, ] print(l) # 函数示例 def get(): print(from get) def put(): print(from put) l1 [get, put] l1[0]()2.函数对象应用重点利用这一特性可以优雅的取代原来的if多分支(elif这种多分支是我们写代码要尽可能避免的。def auth(): print(登陆。。。。。) def register(): print(注册。。。。。) def check(): print(查看。。。。。) def transfer(): print(转账。。。。。) def pay(): print(支付。。。。。) func_dict { 1: auth, 2: register, 3: check, 4: transfer, 5: pay } def interactive(): while True: print( 1 登录 2 注册 3 查看 4 转账 5 支付 ) choice input(: ).strip() if choice in func_dict: func_dict[choice]() else: print(非法操作) interactive() # 是不是比多个if。。.elif。。.简洁明了多了五、闭包函数1.闭包函数说明闭包函数就是定义在函数内部的函数也就是函数的嵌套定义根据字面意思理解闭包函数有两个关键字闭和包 分别是的封闭和包裹。需要注意的重点是闭包函数的作用域关系在函数定义阶段就固定死了与调用位置无关。def outer(): x1 def inner() # 在outer函数内部再定一个函数 # x 2 print(from inner, x) return inner # outer函数返回inner函数对象 f outer( ) # 现在的f是一个全局变量同时是inner函数对象 print(f) x 3 #这个x 3并不能改变inner函数外层的x f() def foo(): x 4 # 这个x 4 同样也不能改变 f () # 全局作用域在任意位置都可以调用 foo()闭包函数可以用外层函数来调用内部的函数打破了函数的层级限制与此同时该函数包含对外部函数作用域中名字的引用。def outer(): name Albert def inner() : print(my name is %s % name) return inner f outer() f()2.为函数体传值的两种方式1以参数的形式的传入#模块的导入后面章节会讲解requests模块就是模拟浏览器向目标站点发请求 import requests def get(url): response requests.get(url) # get方法获取请求返回对象 print(response) if response.status_code 200 # 200是一个状态码代表请求成功 print(response.text) # text方法是获取返回对象的内容 get(https://www.baidu.com)(2以闭包函数的形式闭包函数就是在函数外层再包裹一层作用域由于这个作用域在外层函数内部所以只作用在内层函数上。import requests def outer(url) # 给外层函数传参就相当于 urlhttps://www.baidu.com # urlhttps://www.baidu.com # 这个作用域就是作用在get函数上的 def get(): response requests.get(url) if response.status_code 200: print(response.text) return get baidu outer(https://www.baidu.com) python outer(https://www.python.org) baidu() print() python()简化与总结闭包函数用法def oute(x): def foo(): # foo虽然没有直接传参但是outer函数的作用域赋予了x动态变化 print(x) return foo f_10 outer(10) f_10() f_100 outer(100) f_100()六、装饰器1.装饰器说明器指的工具(只要是工具你就应该想到函数)装饰指的是为被装饰对象添加新功能需要注意的是项目一旦上线之后就应该遵循开发封闭的原则。开放封闭指的是对修改函数内的源代码和调用方式是封闭的对功能的扩展是开放的。看起来有点矛盾但这就是我们要做的。在这样的要求下我们必须要找到一种解决方案能够在不修改一个功能内源代码以及调用方式的前提下为其添加新功能。这就用到了装饰器它能够在不修改被装饰对象源代码与调用方式的前提下为被装饰器对象添加新功能。2.无参装饰器1无参装饰器实现过程无参装饰器指的是装饰器本身没有参数。#要求为index函数添加一个统计时间的功能 import time # 这是一个与时间相关的模块 def index(): time.sleep(3) # 睡3秒 print(welcome to index page) index() #版本一(只有index函数可以使用) import time # 这是一个与时间相关的模块 def index(): time.sleep(3) # 睡3秒 print(welcome to index page) start_time time.time() # 从1970年开始计时的时间戳 index() end_time time.time() print(run time is %s % (end_time - start_time)) # 版本二两个函数都可以使用但是有大量重复代码 def index(): time.sleep(3) print(welcome to index page) def home(name): time.sleep(5) print(welcome %s to home page % name) start_time time.time() index() stop_time time.time() print(run time is %s % (stop_time - start_time)) start_time time.time() home(Albert) stop_time time.time() print(run time is %s % (stop_time - start_time)) # 版本三 (修改了源函数的调用方式) import time def index(): time.sleep(3) print(welcome to index page) def home(name): time.sleep(5) print(welcome %s to home page % name) def wrapper(func): # funcindex start_time time.time() func() # index() stop_time time.time() print(run time is %s % (stop_time - start_time)) wrapper (index) # 版本四 (使用闭包函数不修改源函数调用方式) import time def index(): time.sleep(3) print(welcome to index page) defouter(func) # func最原始的index # func最原始的index def wrapper(): start_time time.time() func() stop_time time.time() print(stop_time - start_time) return wrapper # a outer(index) # outer函数结果可以赋值给任意变量 # b outer (index) # c outer (index) index outer(index) # 赋值给index覆盖原来的indexindex wrapper index() # wrapper() #版本五(解决原函数返回值无效) import time def index(): time.sleep(l) print (welcome to index page) return 1 #假如源函数有一个返回值 def outer(func): #func最原始的home def wrapper(): start_time time.time() res func() # 调用最原始的index stop_time time.time() print(stop_time - start_time) return res return wrapper index outer(index) # 新的indexwrapper res index() # 上一个版本返回值为none print(res) #版本六 (终极版解决有参函数和无参函数通用的问题 import time def index(): time.sleep(l) print(welcome to index page) return 1 def home(name): time.sleep(2) print(welcome %s to home page % name) def timer(func) # 装饰器也是一个函数我们给他一个好听的名字 def wrapper(*args, **kwargs) # wrapper函数有无参数由源函数决定 start_time time.time() res func(*args, **kwargs) stop_time time.time() print(stop_time - start _time) return res return wrapper index timer(index) # 新的indexwrapper home timer(home) # 新的homewrapper home(nameAlbert) # wrapper(nameAlbert) home(Albert) # wrapper(Albert) index() # wrapper() # 无参装饰器模板 def outer(func): def inner(*args, **kwargs): 这里写装饰器逻辑 :param args 任意位置参数 :param kwargs 任意关键参数 :return 一个函数对象 res func(*args, **kwargs) return res return inner2装饰器语法糖import time # 装饰器也是一个函数使用函数必先定义所以装饰器放在最上方 def timer(func): def wrapper(*args, **kwargs): start_time time.time() res func(*args, **kwargs) stop_time time.time() print(stop_time - start_time) return res return wrapper timer # 在被装饰对象正上方单独一行添加相当于执行indextimer(index) def index(): time.sleep(l) print(welcome to index page) return 1 # timer #hometimerhome当不需要装饰器的时候只需注释这一行即可 def home(name): time.sleep(2) print(welcome %s to home page % name) index() home(Albert)3用户认证装饰器import time current_user { username: None, } def auth(func): def wrapper(*args, **kwargs) if current_user[username]: print(已经登陆过了) res func(*args, **kwargs) return res name input(用户名).strip() pwd input(密码 ).strip() if name Albert and pwd 1: print(登陆成功) current_user[username] name res func(*argsi, **kwargs) return res else: print(用户名或密码错误) return wrapper auth def index(): time.sleep(l) print(welcome to index page) return 1 auth def home(name): time.sleep(2) print(welcome %s to home page % name) index() home(Albert)4多个装饰器叠加import time current_user { usernameNone, } def auth(func): def wrapper (*args, **kwargs) if current_user[username]: print(已经登陆过了) res func(*args, **kwargs) return res name input(用户名 ).strip() pwd input(密码 ).strip() if name Albert and pwd 1: print(登陆成功) current_user[username] name res func(*args, **kwargs) return res else: print(用户名或密码错误) return wrapper def timer(func): def wrapper(*args, **kwargs) start_time time.time() res func(*args, **kwargs) stop_time time.time() print(stop_time - start_time) return res return wrapper auth timer # 这样写的话timer只统计index的执行时间 timer # timer统计的是authindex的执行时间 auth def index(): time.sleep(l) print(welcome to index page) return 1 index()3.有参装饰器有参装饰器就是装饰器本身需要一个参数结合我们以前讲过的文件操作其实文件就是存放数据的仓库类似于数据库数据库分很多种常见的有MySQLOraclePostgreSQL和DB2等等在一些项目的需求中不同的数据会分散存储在不同的数据库中这时我们使用基于对象的数据模型(通俗讲就是使用编程语言来操作数据库)操作不同数据库就要执行不同的代码。import time current_user { username None, } def auth(engine): def user_auth(func): def wrapper(*args, **kwargs) if engine file: print(基于文件的认证) if current_user[username]: print(已经登陆过了) res func(*args, **kwargs) return res name input(用户名).strip() pwd input(密码 ).strip() if name Albert and pwd 1: print(登陆成功) current user[username] name res func(*args, **kwargs) return res else: print(用户名或密码错误) elif engine mysql: print(基于MyQL的认证) elif engine ldap: print(基于LDAP的认证) elif engine postgresql: print(基于postgreSQL的认证) return wrapper return user_auth auth(file) # auth装饰器本身是一个函数在语法糖中也可以传参数 def index(): time.sleep(l) print(welcome to index page) return 1 index()4.装饰器补充from functools import wraps def deco(func): wraps(func) # 加在最内层函数正上方 def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper deco def index(): 哈哈哈哈 print(index.__doc__) index()装饰器使用的是闭包函数的原理返回的是和原来函数同名字的函数地址再加上就能调用这个函数所以给我们的感觉是原来的函数没有变化却添加了新的功能其实已经不是原来的函数了你可以把以上代码的第三行注释掉运行代码打印结果为None就是因为你运行的函数已经不是原来的函数了所以这其实是一个伪装饰器要想让装饰器真的是装饰器调用别人写好的包返回结果还是原函数以上写法就是。