python函数学习的总结
python函数
part1
- 函数的作用:
- 函数以功能(完成一件事)为导向
- 随调随用减少代码重复性
- 增强代码可读性
- 函数的结构:
def 函数名(): 函数体
- 函数的返回值
- return:在函数中遇到return直接结束函数
- return将数据返回给函数的执行者(调用)
- return如果返回多个元素是以元组的形式返回给函数的执行者(ret1,ret2,ret3=meet()#元组的拆包)
- 函数的传参:(实参/形参)
- A:实参角度:
- 1.位置参数:从左到右,一一对应
- 2.关键字参数一一对应meet(sex='女',age=25)
- 3.混合传参:一一对应,位置参数一定要在关键字参数的前面
- B:形参角度:
- 1.位置参数与实参角度的位置参数是一种
- 2.默认值参数(设置意义:普遍经常使用的)def meet(weight,sex,age='女'):
- A:实参角度:
- 三元运算符:(简单的 if else )
- c = a if a > b else b
part2
函数的参数2
- 形参角度:
- 万能参数1.*args,约定俗称:args 2.**kwargs
- 函数定义时,代表聚合。他将所有位置参数聚合成一个元组,赋值给了args,函数的定义时:**将所有的关键字聚合到一个字典中,将这个字典赋值给kwargs
- 形参角度的参数的顺序:位置参数,*args,默认参数,仅限关键字参数(了解)(这两个可互换),**kwargs
- 形式参数第四个参数:仅限关键字参数(在*args和**kwargs之间,必须以关键字参数对他进行传值)(了解)
- 在函数调用时,*代表打散(元组),**代表打散(字典)
名称空间
- 名称空间:命名空间
- 全局名称空间(当前py文件)
- 局部名称空间(函数,函数执行时才开辟)(临时名称空间):
- 内置名称空间(builtins.py):python源码给你提供的一些内置的函数,print(),input()
- 加载顺序:
内置名称空间(文件在第一行时内置名称空间就加载进来了)-->全局名称空间-->局部名称空间 - 取值顺序:(就近原则)单向不可逆
LEGB原则:L:local,E:eclose,G:global,B:builtin
(从局部找时)局部名称空间-->全局名称空间-->内置名称空间 - 作用域:
- 两个作用域:
- 全局作用域:内置名称空间全局名称空间
- 局部作用域:局部名称空间(局部作用域可以引用全局作用域的变量(不能改变))
- 不能改变原因:
- 局部作用域不能改变全局作用域的变量:但python解释器读取到局部作用域时,发现了你对一个变量进行了修改的操作,解释器会认为你在局部已经定义过这个局部变量了,他就从局部找这个局部变量,报错了
- 两个作用域:
- 高阶函数:函数的嵌套
globals/locals
a=1
b=2
def func():
name='alex'
age=73
print(globals()) #返回的是字典:字典里面的键值对:全局作用域的所有内容
print(locals()) #返回的是字典:字典里面的键值对,当前作用域的所有内容
print(globals()) #返回的是字典:字典里面的键值对:全局作用域的所有内容
print(locals()) #返回的是字典:字典里面的键值对,当前作用域的所有内容
func()
part3
默认参数陷阱/局部作用域的坑 ***
- 陷阱只针对默认参数是可变的数据类型,那么你无论调用多少次这个默认参数。都是同一个
- 所以把默认参数是可变的数据类型想象成该数据类型保存在一个特殊的名称空间中
- Default values are computed once,then re-used.(官方文档)
- 局部作用域的坑:
- 在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题
你应该在使用之前先定义
- 在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题
global/nonlocal
- global
- 在局部作用域声明一个全局变量
- 修改一个全局变量
- nonlocal(用的少点)
- 不能操作全局变量
- 局部作用域:内层函数对外层函数的局部变量进行修改
函数名的应用***
- 函数名指向的是函数的内存地址
函数名+()就可以执行函数
print(func,type(func))#<class'function'> - 函数名就是变量
- 函数名可以作为容器类数据类型的元素
- 函数名可以作为函数的参数
- 函数名可以作为函数的返回值
格式化输出(新特性3.6版本之后)
name='哈哈'
age=18
msg=f'我叫{name},今年{age}'
print(msg)
- 可以加表达式
- 结合函数写
- !,:{};这些标点不能出现在{}这里面
- 优点:
- 结构更加简化
- 可以结合表达式,函数进行使用
- 效率提升很多
迭代对象/迭代器***
获取一个对象的所以方法
s1='asjbjas'
print(dir(s1))
print('__dir__'in dir(s1))
-
迭代对象小结:(比较直观,存储数据相对少[几百万个对象,8G内存是可以承受的]的一个数据集)
- 字面意思:可以进行循环更新的一个实实在在的值
- 专业角度:内部含有__iter__方法的对象,叫做可迭代对象
-
判断一个对象是不是可迭代对象:'iter'in dir(对象)
str list tuple dict set range -
文件句柄
优点:- 存储的数据直接能显示,比较直观
- 拥有的方法比较多,操作方便
-
缺点:
- 占用内存
- 不能直接通过for循环,不能直接取值(索引,key除外)[其实for循环在底层做了一个小小的转化,就是先将可迭代对象转化成迭代器,然后在进行取值的]
-
应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
-
迭代器小结:
- 字面意思:是一个可以迭代取值的工具,器:在这里当做工具比较合适
- 专业角度:内部含有'iter'方法并且含有'next'方法的迭代对象就是迭代器
-
判断是否是迭代器:'iter'and'next'in dir(对象)
-
文件句柄
优点:- 节省内存
- 惰性机制:next一次,取一个值,绝不过多取值
-
缺点:
- 速度慢
- 取值时不走回头路,只能一直向下取值
应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)
面试题:利用while循环模仿for循环对可迭代对象进行取值的机制(利用迭代器)
将可迭代对象转化成迭代器
l1=[11,22,33,44,55,66,77,88,99,113,25]
obj=iter(l1)
while True:
try:
print(next(obj))
except StopIteration:
break
part4
生成器***
-
生成器的本质就是迭代器
-
唯一的区别:生成器是我们用python代码构建的数据结构
-
迭代器都是提供的,或者转化得到的
-
获取迭代起的2种方法
- python内部提供的
- iter()方法
-
获取生成器的三种方式:
- 生成器函数
- 生成器表达式(自己写的)
- python内部提供的一些
-
生成器函数(一个next()对应一个yield)
-
遍历迭代器的方法:
- 一个一个next()
- for循环
- list()
return yield区别
return:函数中只存在一个return结束函数,并且给函数的执行者返回值
yield:只要函数中有yield那么他就是生成器函数而不是普通函数了
生成器函数可以存在多个yield(yield不会结束生成器函数),一个yield对应一个next.
yield from:将这个列表变成了迭代器返回
在python3中提供一种可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回
列表推导式/生成器表达式***
- 列表推导式:
- 用一行代码构建一个比较复杂有规律的列表
l1=[i for i in range(1,11)]
-
循环模式:[变量(加工后的变量)for 变量 in iterable]
-
筛选模式:[变量(加工后的变量)for 变量 in iterable if 条件]
-
练习题:找到嵌套列表中名字含有两个‘e’的所有名字(有难度)
-
改进:多重循环列表推导式:
-
l1=[j for i in names for j in i if j.count('e')==2]
-
生成器表达式
- 与列表推导式的写法几乎一摸一样,也有循环模式,筛选模式,多层循环构建,写法上[]换成()
-
总结:
列表推导式:- 缺点:
- 有毒,列表推导式只能构建比较复杂并且有规律的列表(不要太着迷)
- 超过三层循环才能构造成功的,就不建议用列表推导式
- 查找模式(debug模式)不行
- 优点:
- 一行构建,简单
- 装逼
- 缺点:
-
生成器表达式和列表推导式的区别:
- 列表推导式比较耗内存,所有数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。
- 得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器
- 列表推导式一目了然,生成器表达式只是一个内存地址
-
其他相关的推导式:
- 字典推导式:
lst1 = ['jay','jj','meet'] lst2 = ['周杰伦','林俊杰','郭宝元'] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic)
- 集合推导式:
集合推导式可以帮我们直接生成一个集合,集合的特点;无序,不重复 所以集合推导式自带去重功能
内置函数1(了解)
- python提供了68个内置函数
- eval()剥去字符串的外衣运算里面的代码,有返回值([在项目中使用可能会带来一些病毒](尤其是1.网络传输的str2.input输入的时候3.sql注入的时候等等绝对不能使用eval))
- exec()与eval()几乎一样,处理代码流
- hash()哈希值(获取一个对象(可哈希对象:int,str,Bool,tuple)的哈希值。)
- help()函数用于查看函数或模块用途的详细说明
5.callable()函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回False,调用对象ojbect绝对不会成功 - bin()将十进制转换成二进制并返回
- oct()将十进制转化成八进制字符串并返回
- hex()将十进制转化成十六进制字符串并返回
- complex()函数用于创建一个值为real+imag*j的复数或者转化一个字符串或数为复数。
- divmod() 计算除数与被除数的结果,返回一个包含商和余数的元组(a//b,a%b)。
- round() 保留浮点数的小数位数,默认保留整数。
- pow() 求xy次幂。(三个参数为xy的结果对z取余)
- bytes() 用于不同编码之间的转化。(b=bytes(s1,encoding='utf-8'))
- ord()输入字符找该字符编码的位置(没超过ascil码超过Unicode编码)
- chr()输入位置数字找出其对应的字符(Unicode编码)
- repr()返回一个对象的string形式(原形毕露)。***(面向对象会用到)
msg='我叫%s'%(s1)
msg='我叫%r'%(s1) - all()可迭代对象中,全都是True才是True
- any()可迭代对象中,有一个True就是True
part5
匿名函数
匿名函数:一句话函数,比较简单的函数
构建匿名函数
func1=lambda a,b:a+b
print(func1(2,5))
内置函数2(重点学习)
- print() #print(self,*args,sep='',end='\n',file=None)
print(1,2,3,sep='|')
print(1,end='') - abs()返回绝对值
- sum()求一个可迭代对象(int)的和(可以设置初始值)
- reversed()将一个序列翻转,返回翻转序列的迭代器(获取一个新的迭代器,对原列表没变化)
- zip()拉链方法(经常出现在面试题)函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组(返回迭代器)
- lst1=[1,2,3]
- lst2=['a','b','c','d']
- lst3=(11,12,13,14,15)
- obj=zip(lst1,lst2,lst3)#python内部提供的迭代器
以下方法最重要
- min()/max()
凡是可以加key的:他会自动的将可迭代对象中的每个元素按照顺序传入key对应的函数中
以返回值比较大小
print(min(dic))#默认会按照字典的键比较大小
def func(a):
return dic[a]# 比较的是字典的值
print(min(dic,key=func))# 每次循环的是字典的键#key=函数名
print(min(dic,key=lambda a: dic[a]))
- sorted()排序函数(返回一个新的)(也有key)
- filter()类似与列表推导式的筛选模式(返回的是一个迭代器)(也有key)
- map()类似与列表推导式的循环模式(#返回的是一个迭代器)(也有key)
闭包
- 封闭的东西:保证数据的安全
def make_averager():
l1=[] #自由变量
def averager(new_value):
l1.append(new_value)
total=sum(l1)
return total/len(l1)
return averager
avg=make_averager() #avg=averager
print(avg(100000))
print(avg(110000))
- 闭包:多用于面试题1.什么是闭包?2.闭包有什么作用?
- 什么是闭包?
- 闭包只能存在嵌套函数中
- 定义:内层函数对外层函数非全局变量的引用(使用),就会形成闭包
- 闭包有什么作用?
- 现象:被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系,自由变量不会在内存中消失
- 闭包的作用:保证数据的安全
- 如何代码判断闭包?
- print(ret.code.co_freevars)
part6
装饰器
标准版的装饰器:
def wrapper(f):
def inner(*args,**kwargs):
""""添加额外的功能:执行被装饰函数之前的操作"""
ret=f(*args,**kwargs)
""""添加额外的功能:执行被装饰函数之后的操作"""
return ret
return inner
-
开放封闭原则:
- 开放:对代码的扩展是开放的
- 封闭:对源码的修改是封闭的
-
装饰器:完全遵循开放封闭原则
-
装饰器:在不改变原函数的代码以及调用方式的前提下,为其增加新的功能
-
装饰器就是一个函数,装饰器的本质就是闭包