python函数总结,你值得拥有
函数总结
函数定义与结构
- 定义:函数就是一个功能,定义一个函数就是编写一个功能,调用一个函数就是实现一个功能。
- 结构
- def 函数名(形参):
- 结构体:缩进,在结构体中尽量少使用print( ),这样为了提高效率
- return:给函数的执行者返回参数
- 没有return:返回None给执行者
- return单值:返回该值给执行者
- return多值:返回一个元组给执行者
函数名的使用
-
函数名+( )就可以执行函数
-
函数名其实就是一个变量
def func(): print('hello') f=func f1=f f() f1()
-
函数名可以作为容器类数据结构的元素
def func1(): print('from fun1') def func2(): print('from fun2') f=[func1,func2] for i in f: i()
-
函数名可以作为参数传递
def func1(f): print('from fun1') f() def func2(): print('from fun2') func1(func2)
-
函数名可以作为return返回
def func1(f): print('from fun1') return f def func2(): print('from fun2') ret=func1(func2) ret()
函数的参数
-
函数在定义调用过程中有两种参数,一种时定义时的形参,另一种是调用时的实参
-
实参包括
- 位置参数:如1,'hello',位置参数一定要在关键字参数前面
- 关键字参数:如name='yzh'
- 混合参数:既包含位置参数又包含关键字参数
-
形参包括
- 位置参数:对应实参的位置参数,如a,b
- *args参数
万能参数*args:其中*在函数定义时代表了聚合,会将除实参对应的形参位置参数外的所有位置参数都集合成一个元组,将元组传递给args
- 默认参数:对应与实参的关键字参数,如实参没传参数给默认参数,则使用自己的默认值,若传了参数,则用实参传递的参数,如name='大白'
- 仅限关键字参数(了解):对应于实参的关键字参数,且实参关键字的变量名必须于关键字的名字一样。
- **kwargs)参数
万能参数**kwargs:其中**在函数定义时代表了聚合,会将除实参对应的形参位置参数外的所有位置参数都集合成一个字典,将字典传递给kwargs
函数实参的排序(位置参数,关键字参数)
形参的排序(位置参数,*args,默认参数/仅限关键字参数,**kwargs)
#func(位置参数,关键字参数) func(1,2,'hello','world',name='yzh',age=18,height=18,c='yzh') #def func(位置参数,*args,默认参数/仅限关键字参数,**kwargs) def func(a,b,*args,name='大白',c,**kwargs)
-
*和**在函数调用时的魔性用法(在调用时代表了打散)
def func(*args,**kwargs): print(args,kwargs) #(1, 2, 3, 'name', 'age') {'name': '大白', 'age': 18} func(*[1,2,3],*{'name':'大白','age':18},**{'name':'大白','age':18}) # *会将列表中的数据一一打散,而对于字典则只会取出字典的键
名称空间与作用域
名称空间
- 名称空间包含全局名称空间,局部名称空间,内置名称空间
- 全局名称空间:当前执行的.py文件
- 内置名称空间:builtins.py
- 局部名称空间:函数被调用时开启,函数结束调用时关闭
- 名称空间加载顺序
- 内置名称空间—>全局名称空间—>局部名称空间
- 名称空间取值顺序(就近原则,单向不可逆,LEGB原则)
- (从局部开始时):局部名称空间—>全局名称空间—>内置名称空间
作用域
-
作用域分为全局作用域和局部作用域
- 全局作用域:全局名称空间+内置名称空间
- 局部作用域:局部名称空间
#注意:局部作用域不能修改全局作用域的值,当python解释器在局部作用域读取到你对一个变量进行修改操作,解释器会认为你在修改前就在局部作用域内定于了该变量,它就会从局部取寻找这个变量,没有找到就报错(一定先定义在使用)
函数嵌套
内置函数(globals( ),locals( ))
-
globals( ):返回一个字典,字典中键值对是全局作用域的所有内容
-
locals( ):返回一个字典,字典中键值对是当前作用域的所有内容
def func(*args,**kwargs): print(args,kwargs) print(locals()) func(*[1,2,3],**{'name':'yzh','age':18}) print(locals()) print(globals())
global+nonlocal
-
global:在局部作用域中声明一个全局变量,使得可以该局部作用域中对声明的全局变量进行修改
a=10 #定义一个全局变量a def func(): global a #在局部作用域中global声明一个全局变量a a-=10 #可以对a进行修改操作 return a print(func())
-
nonlocal:一般在嵌套函数中,主要用于内层函数对外层函数局部变量的修改,但不能修改全局变量
- 注意:不能在局部作用域中先global一个全局变量,然后在嵌套内置函数中再nonlocal一次该变量
a=10 #定义一个全局变量a def func(): a=5 #在局部作用域中声明一个全局变量a def inner(): #在func中再定义一个内层函数inner,构成嵌套函数 nonlocal a a-=4 #可以对局部作用域中的a进行修改操作,不能对全局变量a进行修改 print(a) return a return inner() print(func())
对于函数内部变量对外部变量操作见解:
如果外部变量是可变数据类型,那么可以使用不改变其内存地址的方式对其进行修改(如外部变量为列表,可以使用.append方法)且不需要声明引用(global|nonlocal)
但如果外部变量为不可变数据类型,就必须使用(global|nonlocal)才能对其进行修改
可迭代对象和迭代器
可迭代对象
-
可迭代对象定义:内部含有__ iter __方法的对象,比如:str,list,tuple,set,dict,range
-
判断对象是否为可迭代对象的方法:dir(x),x为对象
print('__iter__' in dir(x)) #True的话说明x就是可迭代对象
-
可迭代对象的特点
- 优点
- 存储的数据可以直接输出,比较直观
- 操作方法多
- 缺点
- 当数据较多时,会占用内存
- 不能直接取值(索引和key除外),必须啊通过for进行一一取值
- 优点
迭代器
-
迭代器的定义:内部含有' __ iter __ ' 以及 ' __ next __ '方法的对象,比如文件句柄
-
判断对象是否为迭代器的方法:dir(x),x为对象
print('__iter__' in dir(x) and '__next__' in dir(x)) #True的话说明x就是迭代器
-
迭代器的特点
- 优点
- 节省内存(读完一条,消失,再读一条)
- 惰性机制(next一次就取一次值)
- 缺点
- 以时间换空间(执行效率慢)
- 不能回去取值,只能往下取值
- 优点
总结
-
迭代器一定是可迭代对象,可迭代对象不一定是迭代器
-
将迭代对象转化为迭代器的方法:iter(x),x为可迭代对象
ls=[1,2,3,4] ls_iter=iter(ls) #通过iter()的方法将可迭代对象ls转化为迭代器 while True: try: for i in range(10): print(next(ls_iter)) #通过next()的方法将迭代器中的值一一取出 except StopIteration: break
-
可迭代对象与迭代器的对比
- 可迭代对象用于许多的操作方法,可对对象进行灵活操作,而且存储的数据清晰明了,所以当你的内存空间足够大且需要灵活操作数据时可以选择将数据存储为可迭代对象
- 但是当数据过多,大到足以撑爆内存时,我们就需要以节省内存为第一考虑点,这时将数据存储为迭代器比较合适
-
利用while循环模拟for循环的迭代器取值
ls=[1,2,3,4] ls_iter=iter(ls) while True: try: print(next(ls_iter)) except StopIteration: break
解析语法与生成器
解析语法
列表解析式
-
定义:用一行代码构建的比较复杂且有规律的列表
-
模式:一类是循环模式,一种是筛选模式
#循环模式 [i for i in iterable可迭代对象] ls=[i for i in range(10)] #筛选模式 [i for i in iterable可迭代对象 if ......] ls=[i for i in range(10) if i>3]
-
特点
- 优点
- 简单方便,一行搞定
- 缺点
- 只能构建比较复杂且必须有规律的列表
- 如果循环次数超过了三层不建议使用列表解析式
- 一旦出错,不好找错误
- 优点
其他解析式
-
字典解析式
dic={i:i**2 for i in range(5)}
-
集合解析式
se={i for i in range(5)}
生成器
-
定义:在python社区中,生成器与迭代器是是一样的,生成器的本质就是迭代器,唯一的区别在于生成器是我们通过pyhon代码构建的数据结构,迭代器是python提供或转化来的
-
获得生成器的途径(三种,生成器函数,生成器表达式,某些内置函数)
-
生成器函数
-
只要函数中有yield或yield from,这是函数就是生成器函数,不再是普通的函数了
-
return 与yield的对比
- return:函数中只能拥有一个return,return意味着函数结束,同时将值返回给函数执行者
- yield:一个生成器函数中可以有多个yield,yield结束不代表生成器函数结束,同时一个yield对应一个next
#yield def func(): ls=[1,2,3] yield ls ret=func() print(next(ret)) #[1, 2, 3] #yield from:将可迭代对象的元素一一拆开 def func(): ls=[1,2,3] yield from ls ret=func() print(next(ret)) #1
- send(了解)
def per(name): print(f'{name} ready to eat') r='next执行后指向here' while 1: food = yield r print(f'{name} start to eat {food}') r = '%s被%s吃了' % (food, name) dog = per('大黄') print(next(dog)) # 第一次必须用next让指针停留在第一个yield后面 # 还可以给上一个yield发送值 ret=dog.send('骨头') print(ret) print(dog.send('狗粮')) print(dog.send('香肠'))
-
send和next()区别:
- 相同点:
- send 和 next()都可以让生成器对应的yield向下执行一次
- 都可以获取到yield生成的值
- 不同点:
- 第一次获取yield值只能用next不能用send(可以用send(None)
- send可以给上一个yield置传递值
- 实际上next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。第一次调用时,一定使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。
- 相同点:
-
-
生成器表达式
- 生成器表达式与列表解析式很相似,唯一的区别在于,列表解析式是[],而生成器表达式是( )
- 通过next,list(),(for i in 生成器表达式)的方式去取值
l=(i,for i in range(10)) #三种取值方式 1.print(list(l)) 2.print(next(l)) 3.for i in l:print(i)
-
一些内置的函数(filter( ), map( ) ,zip( ) reversed( )等)
-
闭包和装饰器
闭包
-
定义:在嵌套函数中,内层函数对外层非全局变量的引用或使用,其中该非全局变量为自由变量
- 自由变量是介于全局变量和局部变量之间的一种特殊变量,它会与内层函数形成一个绑定关系,且会在全局作用域中形成一个独特的空间来单独存放自由变量
-
作用:保证数据的安全
-
怎么判断闭包:使用(函数名().__ code __. co _freevars),会以元组的形式返回自由变量
#第一种,内层函数对外层非全局不可变类型变量进行引用操作 def func(a,b): def inner(): print(a,b) return inner ret=func(1,2) print(ret.__code__.co_freevars) #('a','b') #第二种,内层函数对外层非全局不可变类型变量进行修改操作 def func(): a=10 def inner(): nonlocal a #记得加上nonlocal a-=5 print(a) return inner ret=func() print(ret.__code__.co_freevars) #('a',) #第三种,内层函数对外层非全局可变类型变量进行修改或引用操作 def func(): ls=[] def inner(): ls.append(1) print(ls) return inner ret=func() print(ret.__code__.co_freevars)
装饰器
-
定义:装饰器的本质就是闭包,完全遵循开放封闭原则,在不改变函数的源码以及调用方法的情况下为函数增加新的功能
- 开放封闭原则:对函数的功能拓展是开放的,对函数的源码是封闭的
-
使用途径:进入页面的登录认证等
-
装饰器的标准代码
def wrapper(f): def inner(*args,**kwargs): #执行被装饰函数前添加的新功能 ret=f(*args,**kwargs) # 执行被装饰函数后添加的新功能 return ret return inner @wrapper #等同于func=wrapper(func) def func(): return 666
lambda函数+内置函数
lambda函数
-
lambda函数也叫匿名函数,一句话函数,所谓匿名,就是与关键字def函数相比,没有函数名称,lambda函数多与内置函数,列表推导式相结合
- lambda[参数]:表达式:表达式也是lambda函数的返回值
-
特点
- lambda后没有函数名,但是可以将整个lambda函数传给一个变量名,这个变量名也就成了新的函数名
fun=lambda x:x**2 print(fun(2))
- 整个函数在一行内实现所有定义,简单方便,有效减少冗余代码
内置函数
-
python包含了68个内置函数
-
了解:eval() exec() hash() help() callable() int() float() complex() bin() oct() hex() chr() ord() round() divmod() pow() all() any() bytes() repr() format() frozenset() globals() locals() id() input() print() str() list() tuple() iter() next() dict() set() sum() range() abs() enumerate() type() dir() reversed() zip()等
-
重点:带key的,内置函数中凡是带key的,它都自动的将可迭代对象的元素按照顺序传入key对应的函数中
- max(*args,key=None)
- min(*args,key=None)
ls=[-1,2,3,-7] print(max(ls,key=lambda x:abs(x))) print(min(ls,key=lambda x:abs(x)))
- sorted(*args,key=None,reverse=True/False):reverse=True表示从大到小,False表示从小到大,不会改变原迭代对象的顺序
ls=[[1,2],[4,5],[8,3],[9,3]] print(sorted(ls,key=lambda x:(x[1],x[0]),reverse=False)) #注意(x[1],x[0])表示,如果x[1]一致,就使用x[0]
- filter(key,*args):返回的是一个生成器
ls=[1,2,4,3,7,5,9] i=filter(lambda x:x>3,ls) print(list(i))
- map(key,*args):返回的是一个生成器,与列表推导式相似,但前者返回的是生成器,后者返回列表
ls=[1,2,4,3] i=map(lambda x:x**2,ls) print(list(i))
- reduce(key,*args):reduce必须从functools模块中导入
from functools import reduce def func(x,y): return x+y ls=[1,2,3,4] print(reduce(func,ls)) #第一次:x=1,y=2 获取结果x+y=3,将3作为下一个x的参数 #第二次:x=3,y=3 获取结果x+y=6,将6作为下一个x的参数 #第三次:x=6,y=4 获取结果x+y=10,将10作为最终的结果返回reduce()
-
在面向对象中会谈及:classmethod() delattr() getattr() hasattr() issubclass() isinstance() object() property() setattr() staticmethod() super()
-
内置函数小结
结果会得到迭代器的内置函数有:reversed( ),zip( ),filter( ),map( )
带key的内置函数:min( ),max( ),sorted( ),filter( ),map( ),reduce( )