一 函数对象
一 函数是第一类对象,即函数可以当作数据传递
#1 可以被引用
#2 可以当作参数传递
#3 返回值可以是函数
#3 可以当作容器类型的元素
二 利用该特性,优雅的取代多分支的if
def foo(): print('foo') def bar(): print('bar') dic={ 'foo':foo, 'bar':bar, } while True: choice=input('>>: ').strip() if choice in dic: dic[choice]()
二 函数嵌套
一 函数的嵌套调用
def max(x,y): return x if x > y else y def max4(a,b,c,d): res1=max(a,b) res2=max(res1,c) res3=max(res2,d) return res3 print(max4(1,2,3,4))
二 函数的嵌套定义
def f1(): def f2(): def f3(): print('from f3') f3() f2() f1() f3() #报错,为何?请看下一小节
三 名称空间与作用域
一 什么是名称空间?
名称空间:存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)
二 名称空间的加载顺序
python test.py
#1、python解释器先启动,因而首先加载的是:内置名称空间
#2、执行test.py文件,然后以文件为基础,加载全局名称空间
#3、在执行文件的过程中如果调用函数,则临时产生局部名称空间
三 名字的查找顺序
局部名称空间--->全局名称空间--->内置名称空间 #需要注意的是:在全局无法查看局部的,在局部可以查看全局的,如下示例 # max=1 def f1(): # max=2 def f2(): # max=3 print(max) f2() f1() print(max)
四 作用域
#1、作用域即范围 - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效 - 局部范围(局部名称空间属于该范围):临时存活,局部有效 #2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下 x=1 def f1(): def f2(): print(x) return f2 x=100 def f3(func): x=2 func() x=10000 f3(f1()) #3、查看作用域:globals(),locals() LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__ locals 是函数内的名字空间,包括局部变量和形参 enclosing 外部嵌套函数的名字空间(闭包中常见) globals 全局变量,函数定义所在模块的名字空间 builtins 内置模块的名字空间
闭包函数
一 什么是闭包?
# 闭包函数 # 闭指的是:该函数是一个内部函数 # 包指的是:指的是该函数包含对外部作用域(非全局作用域)名字的引用 def outter(): x = 1 def inner(): print(x) return inner f=outter() def f2(): x=1111111 f() f2() def f3(): x=4444444444444 f() f3()
二 闭包的意义与应用
# 为函数体传值的方式一:使用参数的形式 def inner(x): print(x) inner(1) inner(1) inner(1) # 为函数体传值的方式二:包给函数 def outter(x): # x=1 def inner(): print(x) return inner f=outter(1) f()
#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域 #应用领域:延迟计算(原来我们是传参,现在我们是包起来) import requests def outter(url): # url='https://www.baidu.com' def get(): response=requests.get(url) if response.status_code == 200: print(response.text) return get baidu=outter('https://www.baidu.com') python=outter('https://www.python.org') baidu() baidu() python() python()
装饰器
装饰器就是闭包函数的一种应用场景
一 为何要用装饰器
#开放封闭原则:对修改封闭,对扩展开放
二 什么是装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
三 装饰器的使用
import time def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timmer def foo(): time.sleep(3) print('from foo') foo()
装饰器语法
def deco(func): def wrapper(*args,**kwargs): #原被装饰函数为有参函数传参 res=func(*args,**kwargs) #传入参数给原函数用 return res #原被装饰函数有返回值 return wrapper #被装饰函数的正上方,单独一行 @deco1 @deco2 @deco3 def foo(): pass foo=deco1(deco2(deco3(foo)))
#装饰器语法糖 # 在被装饰对象正上方,并且是单独一行写上@装饰器名 import time def timmer(func): #func=最原始的index def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper @timmer # index=timmer(index) def index(): print('welcome to index') time.sleep(1) return 123 @timmer # home=timmer(home) def home(name): print('welcome %s to home page' %name) time.sleep(2) res=index() home('w')
有参装饰器
import time current_user={'user':None} def auth(engine='file'): def deco(func): def wrapper(*args,**kwargs): if current_user['user']: #已经登陆过 res = func(*args, **kwargs) return res user=input('username>>: ').strip() pwd=input('password>>: ').strip() if engine == 'file': # 基于文件的认证 if user == 'han' and pwd == '123': print('login successful') # 记录用户登陆状态 current_user['user']=user res=func(*args,**kwargs) return res else: print('user or password error') elif engine == 'mysql': print('基于mysql的认证') elif engine == 'ldap': print('基于ldap的认证') else: print('无法识别认证来源') return wrapper return deco @auth(engine='mysql') # @deco #index=deco(index) #index=wrapper def index(): print('welcome to index page') time.sleep(1) @auth(engine='mysql') def home(name): print('welecome %s to home page' %name) time.sleep(0.5) index() home('han')
匿名函数
一 什么是匿名函数?
匿名就是没有名字 def func(x,y,z=1): return x+y+z 匿名 lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字 func=lambda x,y,z=1:x+y+z func(1,2,3) #让其有名字就没有意义
二 有名字的函数与匿名函数的对比
#有名函数与匿名函数的对比 有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能 匿名函数:一次性使用,随时定义 应用:max,min,sorted,map,reduce,filter
max min map filter sorted 与匿名函数应用
#max min map filter sorted salaries={ 'egon':3000, 'alex':100000000, 'wupeiqi':10000, 'yuanhao':2000 } # max的工作原理 #1 首先将可迭代对象变成迭代器对象 #2 res=next(可迭代器对象),将res当作参数传给key指定的函数,然后将该函数的返回值当作判断依据 # def func(k): # return salaries[k] # # print(max(salaries,key=func)) #next(iter_s) #'egon', v1=func('egon') #'alex', v2=func('alex') #'wupeiqi', v3=func('wupeiqi') #'yuanhao', v4=func('yuanhao') # salaries={ # 'egon':3000, # 'alex':100000000, # 'wupeiqi':10000, # 'yuanhao':2000 # } # print(max(salaries,key=lambda k:salaries[k])) #next(iter_s) # print(min(salaries,key=lambda k:salaries[k])) #next(iter_s) # l=[10,1,3,-9,22] # l1=sorted(l,reverse=False) # print(l1) # l2=sorted(l,reverse=True) # print(l2) # salaries={ # 'egon':3000, # 'alex':100000000, # 'wupeiqi':10000, # 'yuanhao':2000 # } # # print(sorted(salaries,key=lambda k:salaries[k],reverse=True)) names=['张明言','刘华强','苍井空','alex'] # map的工作原理 #1 首先将可迭代对象变成迭代器对象 #2 res=next(可迭代器对象),将res当作参数传给第一个参数指定的函数,然后将该函数的返回值当作map的结果之一 # aaa=map(lambda x:x+"_SB",names) # print(aaa) # print(list(aaa)) # print([name+"_SB" for name in names]) # filter的工作原理 #1 首先将可迭代对象变成迭代器对象 #2 res=next(可迭代器对象),将res当作参数传给第一个参数指定的函数,然后filter会判断函数的返回值的真假,如果为真则留下res names=['alexSB','egon','wxxSB','OLDBOYSB'] # print([name for name in names if name.endswith('SB')]) aaa=filter(lambda x:x.endswith('SB'),names) print(aaa) print(list(aaa))
内置函数
#注意:内置函数id()可以返回一个对象的身份,返回值为整数。这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以内存地址为准。is运算符用于比较两个对象的身份,等号比较两个对象的值,内置函数type()则返回一个对象的类型 #更多内置函数:https://docs.python.org/3/library/functions.html?highlight=built#ascii