Python学习笔记——函数
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
函数是组织好的可重复使用的用来实现单一或相关联功能的代码段。能提高应用的模块性和代码的重复利用率。
定义函数
定义函数使用关键字def后接函数名再后接放在圆括号中的可选参数列表最后是冒号。
函数的组成
函数代码块以 def 关键词开头后接函数标识符名称和圆括号 ()。
任何传入参数和自变量必须放在圆括号中间圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号 : 起始并且缩进。
return [表达式] 结束函数选择性地返回一个值给调用方不带表达式的 return 相当于返回 None。
函数的参数
形参是从函数的角度来说的。实参是从调用的角度来说的。在调用时传入的参数就是实参。
传递实参
向函数传递实参的方式很多可使用位置实参这要求实参的顺序与形参的顺序相同也可使用关键字实参其中每个实参都由变量名和值组成还可使用列表和字典。
位置实参
你调用函数时Python必须将函数调用中的每个实参都关联到函数定义中的一个形参。为此最简单的关联方式是基于实参的顺序。这种关联方式被称为位置实参。
位置实参的顺序很重要使用位置实参来调用函数时如果实参的顺序不正确结果可能出乎意料。
关键字实参
关键字实参是传递给函数的名称 — 值对。使用关键字参数允许函数调用时参数的顺序与声明时不一致因为 Python 解释器能够用参数名匹配参数值。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(animal_type='hamster', pet_name='harry')
注意 使用关键字实参时务必准确地指定函数定义中的形参名。
默认参数
编写函数时可给每个形参指定默认值。调用函数时如果没有传递参数则会使用默认参数。
def describe_pet(pet_name, animal_type='dog'):
"""显示宠物的信息"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(pet_name='willie') #调用函数时使用默认值
注意 使用默认值时在形参列表中必须先列出没有默认值的形参再列出有默认值的实参。这让Python依然能够正确地解读位置实参。
不定长参数
通过元组或列表的解包参数的方式定义参数与调用方式fun(*参数)
这种定义方式只有一个形参当被调用时形参会被定义为一个元组。传入的实参都是这个元组类型的形参的元素。在函数体中可以通过访问形参中的元素来获取传入的实参。
1函数的调用传入任意多的实参
def recoder(*person): #定义一个函数形参person的类型为元组
print('姓名', person[0],'年纪', person[1] ) #函数的内容为一句代码实现将指定内容输出
recoder("Gary", "32") #调用函数传入两个参数。输出“姓名Gary年纪32”
注意
这种方式无法通过指定形参名称来传入实参而且传入的实参顺序与形参内部元素的顺必须一一对应
因为接收参数的类型是元组所以用这种方式传值后不能对形参内容进行修改。
2函数的调用传入列表或元组
Mylist = ["Gary", "32"]
#调用时传入的*Mylist是一个列表的类型前面加个星号。
recoder (*Mylist) #调用函数, 传入list作为实参。输出姓名Gary年纪32
通过字典的解包参数方式, 定义参数与调用方式fun**参数
这种方式是将形参当成一个字典类型变量来接收实参。这样传入的实参和对应的名字就可以放到这个字典里。形参为字典中元素的key, 实参为字典中元素的value。
def recoder(**person): #定义一个函数形参person的类型为元组
print('姓名', person['name'],'年纪', person['age'] )
recoder(age=32 , name ="Gary") #指定形参名称调用函数。输出“姓名Gary年纪32”
Mydic = {"name":"Gary","age":32}
recoder(**Mydic) #调用时, 还可以直接将字典传入。
函数的属性
文档字符串
在函数体中常会在开始位置放置一个行字符串用来说明函数的功能及调用方法。这个字符串叫作函数的文档字符串docstring可以使用代码print函数名._doc_将其输出。而_doc_则为函数的属性并且这个属性可修改。
def getrecoder(): #定义一个函数
'''该函数是返回用户名字和年龄'''
name =’ Gary ’
age = 32
return name, age
print(getrecoder._doc_) #输出文档字符串该函数是返回用户名字和年龄
getrecoder._doc_="新文档字符串" #修改函数的_doc_属性
print(getrecoder . _doc_) #打印文档字符串输出新文档字符串
类似这样的功能在定义函数的同时还可以为函数添加自定义属性。每个函数都有个默认的字典_dict_用于放置函数的属性。
def recoder(strname,*,age): #定义一个函数
print('姓名',strname,'年纪',age) #函数的内容
print(recoder._dict_) #函数没有任何属性_dict_为空输出{}
recoder.attr="person" #为函数添加属性attr
print(recoder._dict_) #输出{'attr':'person'}
print(recoder.attr) #直接取出属性值输出person
直接在函数名后面加个点就可以在后面直接添加属性获取该属性时也同样是在该函名后面加个点再跟上函数的具体属性名。这种方式可以在使用函数时传递更多的信息。
函数的本质
函数的本质时对象可以被调用的函数都会继承可调用的方法call使用函数callable可以检查函数是否被调用。
def recoder(strname,*,age): #定义一个函数
print('姓名',strname,'年纪',age) #函数的内容
print(callable(recoder)) #函数是否被调用输出True
函数的分类
从用户角度
内置函数Python内部自带的函数
自定义函数用户自己编写的函数
从功能角度
生成器函数
一般函数
从形式角度
普通函数使用def定义
匿名函数使用lambda关键字来定义
可迭代函数一种循环迭代功能的内置函数
递归函数
偏函数使用partial关键字定义
在函数调用中检查参数
在函数调用中默认是不检查参数的类型的通过使用isinstance函数可以对参数进行检查。
isinstance(obj , class_or_tuple)
第一个参数obj传入待检查的具体对象。
第二个参数class_or_tuple待检查的具体类型, 可以是个类或者元组。
确切的说, 该函数的功能是检查obj是否为class_or_tuple的一个实例。
在使用的过程中, 直接在函数体的开始部分使用isinstance判断一下参数即可。isinstance的第一参数传入带判断的形参第二个参数就是合法的类型。
def recoder(strname,age): #定义一个函数recoder
if not isinstance(age,(int,str)): #对参数类型进行检查, 合法的类型为int和str
raise TypeError('bad operand type') #如采类型错误, 使用raise函数进行报错
print('姓名', strname, '年纪', age)
recoder("Gary", age=32.2) #调用时传入了age为float类型
函数调用中的参数传递及影响
函数调用时, 实参传递到形参的过程中有两种情况一一传值和传用。
对于不可变对象, 函数调用时, 是传值。意味着函数体里可以使用实参的值, 但不能改变实参。
对于可变对象, 函数调用时, 是传引用。意味着在函数体里还可以对实参进行修改。
匿名函数与可迭代函数
匿名函数一般适用于单行代码函数。
匿名函数的作用是, 把某一简单功能的代码封装起来, 让整体代码更规整一些。一般只调用一次不再需要, 所以名字也省略了, 于是变成了匿名函数。
匿名函数是以关键宇lambda开始的, 它的写法如下
Lambda参数1, 参数2...表达式
上面的写法中, 表达式的内容只能是一句话的函数, 而且不能存在return关键字。
可迭代函数就是一种有循环迭代功能的内置函数包括reduce、map和filter等。
匿名函数与reduce函数的组合应用
reduce函数本质上也可以算作一个内嵌循环的函数。
reduce函数一般用于归并性任务。
reduce函数的能是按照参数sequence中的元素顺序, 来依次调用函数function, 并且每次调用都会向其传入两个参数一个是sequence序列中的当前元素, 另一个是sequence序列中上一个元素在函数function中的返回值。
reduce( function, sequence, [initial])
function要回调的函数。
sequence一个“序列”类型的数据。
第三个参数可选, 是一个初始值。
使用reduce函数与匿名函数的结合写法, 来实现求l~100的和
from functools import reduce #导入reduce函数
print(reduce(lambda x, y:x+y, range(l,101))) #第一个参数是个匿名函数, 实现两个数相加, 输出5050
匿名函数与map数的组合应用
map函数的功能是将参数sequence内部的元素作为参数, 并按照sequence序列的顺序, 依次调用回调函数function。
map函数一般用于映射性任务
map(function, sequence[, sequence, ……]
function要回调的函数。
sequence一个或多个“序列”类型的数据。
该函数返回值为一个map对象。在使用时, 得用list或tuple等函数进行转化。
1、使用map函数处理一个序列数据
当map后面直接跟一个序列数据时, 直接将该序列数据中的元素作为参数, 依次传入前面的函数。例如
t = map(lambda x: x ** 2, [1,2,3,4,5]) #使用map函数, 对列表[1,2,3,4,5]的元素求平方值。返回值赋给t
print(list(t)) #将t转成列表类型, 并打印。输出[1,4,9,16,25]
2、使用map函数处理多个序列数据
当map后面直接跟多个序列数据时, 处理函数的参数个数要与序列数据的个数相同。
运行时, map内部依次提取每个序列数据中的元素, 一放到所提供的处理函数中, 直到循环遍历完最短的那个序列。例如
t = map(lambda x,y: x + y, [1,2,3,4,5],[1,2,4,5]) #遍历最小的列表[1,2,4,5]实现两个列表的元素相加
print(list(t)) #将t转成列表类型, 并打印。输出[2479]
匿名函数与filter函数的组合应用
filter函数的功能是对指定序列进行过滤。
fliter函数一般用于过滤性任务。
filter函数的定义
filter函数有两个输入参数一个是filter的处理函数, 另一个是待处理的序列对象。在运行时, filter函数会把序列对象中的元素依次放到filter的处理函数中。如果返回True, 就留下, 反之就舍去。
其定义如filter(function or None, sequence)
function为filter的处理函数, 在filt町的内部以回调的方式被调用。返回布尔型。意味着某元素否要留下。
sequence一个或多个“序列”类型的数据。
filter函数的使用
filter函数的返回值是一个filter类型, 需要将其转成列表或元组等序列才可以使用。例如
t=filter(lambda x:X%2==0,[1,2,3,4,5,6,7,8,9,10]) #筛选出一个列表中为偶数的元素
print(list(t)) #转成列表, 并打印。输出[2,4,6,8,10]
如果filter的处理函数为None, 则返回结果和sequence参数相同。例如
t=filter(None,(1,2,3,4,5,6,7,8,9,10]) #过滤一个列表中为偶数的元素
print(list(t)) #转成列表, 并打印。输出【1,2,3,4,5,6,7,8,9,10]
当fliter的处理函数为None时, 返回的元素与原序列一样。从功能上来说, 没有什么意义从代码框架的角度来说, 会更有扩展性。当处理函数的输入是变量时, 则可以把filter函数的调用部分代码固定下来。为处理函数变量值不同的过滤函数, 以实现不同的处理功能。
可迭代函数的返回值
每个可选代函数返回的值都属于一个生成器对象。
生成器对象会有一个_next_方法。调用该方法可以取到内部的各个值。最终_next_通过Stoplteration异常来停止迭代。
#过滤列表中能被4整除的元素 返回4、8
t=filter (lambda x:x %4==0 , [l, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(t._next_()) #使用_next_()方法获取元素输出4
print(t._next_()) #使用_next_()方法获取元素输出8
print(t._next_()) #已经没有元素返回Stoplteration
生成器对象与迭代器对象的主要区别在于生成器对象只能选代一次而选代器对象可以法代多次。所以, 对可选代函数的结果只能取一次, 无法再次提取。这一点一定要注意。
偏函数
偏函数是对原始函数的二次封装, 它是属于寄生在原始函数上的函数。偏函数可以理解为重新定义一个函数, 向原始函数添加默认参数。有点像面向对象中的父类与子类的关系。
偏函数的定义partial(func , *args, **keywords)
func要封装的原函数
第二个参数为一个元组或列表的解包参数代表传入原函数的默认值可以不指定参数名
第三个参数为一个字典的解包参数代表传入原函数的默认值指定参数名。
偏函数的作用是, 为其原函数指定一些默认的参数。调用该偏函数, 就相当于调用了原函数, 同时将默认的参数传入。在使用partial前, 必须引入functools模块
偏函数的使用
from functools import partial
def recoder(strname , age):
print('姓名', strname, '年纪', age)
Garyfun = partial(recoder , strname ="Gary") #定义一个偏函数
Garyfun(age = 32) #调用偏函数输出“姓名Gary年纪32“
偏函数的本质是, 将函数式编程、默认参数和冗余参数结合在一起。通过偏函数传入的参数调用关系, 与正常函数的参数调用关系是一致的。
偏函数通过将任意数量顺序的参数, 转化为另一个带有剩余参数的函数对象, 从而实现了截取函数功能偏向〉的效果在实际应用中, 可以使用一个原函数, 然后将其封装多个偏函数, 在调用函数时全部调用偏函数。这样的代码可读性提升了很多。
生成器函数
生成器与迭代器区别
迭代器是所有的内容都在内存里, 使用next函数来依次往下遍历。
生成器不会把内容放到内存里, 每次调用next函数时, 返回的都是本次计算出来的那个元素, 用完之后立刻销毁。
整个序列占用内存特别大时, 使用生成器对象会节约内存当系统的运算资源不足时, 使用迭代器对象会节约运算资源。
生器函数Generator是一种特殊的函数, 是用来创建生成器对象的工具。生成器函数使用yield语句返回, 返回值是一个生成器对象。
def Reverse(data} : #定义一个函数实现字符串反转
for idx in range(len(data)-1 , - 1, -1) :
yield data [ idx ] #使用yield返回具体的一个元素
for c in Reverse('Python'):
print(c, end = ' ') #输出 n o h t y P