十六、python里的函数
十六、python里的函数
python里函数分为内置函数与自定义函数
内置函数:如int(),str(),len()等,所有的内置函数参考https://docs.python.org/3/library/functions.html
自定义函数的定义与调用(重点)
def funct(): # 函数名(),括号里可以写参数,也可以不写
"""函数说明或注释""" # 说明可以不写,大型程序为了程序可读性最好写
print("xxx") # 函数代码主体
print("xxx") # 函数代码主体
print("xxx") # 函数代码主体
return 0 # 函数返回值,可有可无
funct() # 调用函数的方式(调用函数也就是执行函数内部的代码)
函数传参格式
定义函数传参格式
def 函数名(形参1,形参2):
函数体
调用格式:
函数名(实参1,实参2)
函数参数传递的顺序和个数必须一致
实例
def wash(a, b, c):
print("加水{}升".format(a))
print("搓洗{}分钟".format(b))
print("脱水{}分钟".format(c))
wash(3, 40, 10)
wash(b=40, a=3, c=10) # 关键字参数可以换位置
默认参数(缺省值)
含义:为参数提供默认值,调用函数时可不传该默认参数的值
注意:所有的位置参数必须出现在默认参数前,包括函数定义和调用
def connect_ssh(host,usr,password,port=22): # port=22为默认参数
print(host, usr, password, port)
host = input("input host:")
user = input("input user:")
password = input("password")
connect_ssh(host,user,password,33) # 不用再传port的值,默认就是22,也可以传一个新的值替代22
#设置默认值,没有传值会根据默认值来执行代码,传了值会根据传入的值来执行代码
可变参数
含义:传入参数的数量是可以改变的,可以传入多个,也可以不传
格式:
def func(*args):
print(args) # 以元组的形式接收
func(1,2,3,4,5)
案例
def funct1(*args): # args可改成其他参数名,就是一个形参
num1 = 0
for i in args:
if isinstance(i,int):
num1 += i
print(num1)
funct1(1,2,3,4,"a","v")
关键字参数
格式:def func(**kwargs) #kwargs可改成其他参数名,就是一个形参
作用:可以扩展函数的功能
def func(**kwargs):
print(kwargs)
print(type(kwargs)) # 以字典形式接收
func() # 空字典
func(name='zhangsan',age=18) # 传值的时候,采用键=值的形式
嵌套函数
实例1
def bbb():
print("bbb")
aaa()
def aaa():
print("aaa")
bbb()
实例2
def aaa():
print("aaa")
def bbb():
print("bbb")
aaa()
bbb()
实例1与实例2都是同样打印出
bbb
aaa
请问下面的代码有没有问题
def bbb():
print("bbb")
aaa()
bbb()
def aaa():
print("aaa")
报错NameError: name 'aaa' is not defined
总结:
函数要先定义才能调用
函数类似一个变量,定义函数就是把函数体内的代码在内存开辟一个空间存放进去,然后可以通过函数名来调用
调用函数其实就是执行函数体内的代码
小结
1.为什么要传参?
每次调用函数可能会有不同的需求,传参就相当于是和函数做交互,传不同的值给函数来实现不同的需求
2.形参和实参
3.位置参数
实参与形参按顺序一一对应
4.关键字参数
在实参里也要写上形参的名字,这样做可以改变顺序
5.默认值参数
大部分情况下值不变,极少数值不一样的情况下可以使用默认值参数。
默认值参数就是不传值就用默认的,传了值就用传的值。
6.可变长参数
参数个数不确定的情况就用可变长参数
函数返回值(重点)
函数的功能要专一,一个函数只能完成一个功能
函数返回值额度作用:把函数的执行结果返回给需要调用的地方
函数return返回的是一个值,所以要赋值给一个变量,然后通过调用变量得到返回值
函数返回值写在函数体的最后,因为函数返回值意味着函数的结束
def funct1(*args):
num1 = 0
for i in args:
if isinstance(i,int):
num1 += i
return num1 # return返回的值才可以被调用
sum = funct1(1,2,3,4,5,5)
if sum > 10:
print("大了")
else:
print("小了")
小结
函数的结果要被其他地方调用,就不要在函数里用print打印,而是用return做成返回值,再把这个返回值赋值给一个变量,让调用者使用这个变量就是在使用这个函数的结果。
函数变量的作用域:全局变量,局部变量
全局变量:函数外部定义的变量,在整个文件中都是有效的
局部变量:函数内部定义的变量,从定义位置开始到函数定义结束位置有效
实例
name="zhangsan" #全局变量
def change_name():
name="lisi" #这个变量只能在函数内生效,也就是局部变量(可以说这个函数就是这个变量的作用域)
gender="male"
print(name)
change_name()
print(name) #打印出zhangsan
print(gender) # 这句会报错,因为它是局部变量,在外面调用不了
global关键字
作用:global可以对全局变量进行修改,也可以在局部作用域中声明一个全局变量
def change_name():
global name, gender # 这句可以把name改为全局变量,但不建议这样用,如果多次调用函数,这样很容易混乱,容易与外部的变量冲突
name="lisi"
gender="male"
print(name)
change_name() # 这句的结果为lisi,调用函数内部的print(name)得到的结果
print(name) # 这句的结果为lisi
print(gender) # 可以调用gender变量了,能打印出结果
nonlocal
作用:只能在嵌套函数中使用,用来声明外层的局部变量,,在外部函数先进行声明,内部函数进行nonlocal声明
a=10 #全局变量
def outer():
a=5 # 局部变量
def inner():
a=20
print("inner函数中a的值",a)
inner()
print("outer函数中a的值",a)
outer()
匿名函数
语法:函数名 = lambda 形参 : 返回值(表达式)
调用:结果 = 函数名(实参)
普通函数
def add(a,b):
return (a+b)
print(add(1,2))
匿名函数
add = lambda a,b:a+b # a,b就是匿名函数的形参,a+b就是返回值的表达式
# lambda不需要写return来返回值,表达式本身结果就是返回
print(add(1,2))
lambda的参数形式
1.无参数
funa = lambda :'一杯水'
print(funa())
2.一个参数
funb = lamba name:name
print(funb('zhangsan'))
3.默认参数
func = lamba name,age=18:(name,age)
print(func('zhangsan'))
print(func('zhangsan',20))
fune = lambda a,b,c=10:a+b+c
print(fune(1,2))
print(fune(1,2,3))
递归函数(拓展)
函数可以调用其他函数,也可以调用自己,如果一个函数自己调用自己,就是递归函数,但递归也有次数上限(保护机制),所以递归需要一个结束条件
在计算机中,函数调用通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的。所以递归调用的次数过多,会导致栈溢出。
常用内置函数
import builtins
# print(dir(builtins)) # 查看有哪些函数
# 大写字母开头一般是内置常量名,小写字母开头一般是内置函数名
# abs() 返回绝对值
print(abs(-10))
# sum() 求和
# print(sum(123)) 报错,整型不是可迭代对象,sum函数里面要放可迭代的对象,注意:字符不可以进行相加
print(sum((1,2,3))) #元祖
print(sum({1,2,3})) #集合
print(sum([1,2,3])) #列表
# min() 求最小值
# max() 求最大值
print(min(1,2,3,4))
print(max(1,2,3,4))
print(min(-8,4,key=abs)) # 传入了绝对值函数,则参数就会先求绝对值再取较大值
# zip() 将可迭代对象作为参数,将对象中对应的元素打包成一个个元组
li = [1,2,3]
li2 = ['a','b','c','d']
print(zip(li,li2))
# 第一种方式,通过for循环打印
for i in zip(li,li2):
print(i) # 元素会一一对应输出元组,如果元素个数不一致,就按照长度最短的返回
# 第二种方式,转换成列表打印
print(list(zip(li,li2)))
# 注意:必须是可迭代对象
# map() 可以对可迭代对象中的每一个元素进行映射,分别去执行
# map(func,iter1) func--自己定义的函数, iter1--要放进去迭代的对象,简单来说就是对象中的每一个元素都会去执行这个函数
li = [1,2,3]
def func(a):
return a * 5
map=map(func,li)
print(map)
# 方法一:
# for i in map:
# print(i)
# 方法二:
# print(list(map))
# reduce() 先把对象中的两个元素取出,计算出一个值保存着,接下来把计算值跟第三个元素进行计算
# 需要先导包
from functools import reduce
# reduce(function,sequence) function--函数:必须是有两个参数的函数,sequence--序列:必须是可迭代对象
li2=[1,2,3,4]
def add(x,y):
return x+2*y
res=reduce(add,li2)
print(res)
# 拆包:对于函数中的多个返回数据,去掉元组,列表或字典,直接获取里面数据的过程
tua = (1,2,3,4)
print(tua)
# 方法一:
a,b,c,d = tua
print('a=',a,'b=',b,'c=',c,'d=',d)
# 要求元组内的个数与接收的变量个数相同,对象内有多少个数据就需要定义多少个变量接收,如果接收的变量和元组的数据不一样,就会报错too many values to unpack (expected 2)
# 方法二
a,*b=tua
print('a=',a,'b=',b)
def func(a,b,*args):
print(a,b)
print(args,type(args))
func(1,2,3,4,5,6,7)