目录
一、函数概述
(一)认识函数
在一个完整的项目中,某些功能会反复的使用。那么会将功能封装成函数,当我们要使用功能的时候直接调用函数即可。
函数的本质:就是对功能的封装。
使用函数的优点:
1、简化代码结构,增加了代码的复用度(重复使用的程度)
2、如果想修改某些功能,或者修改某个BUG,只需要修改对应的函数即可。
(二)定义函数
格式:
def 函数名(参数列表):
语句
return 表达式
函数格式解析:
def和函数名()中间有几个空格无所谓
def:函数代码块以def关键字开始
函数名:遵循标识符规则
():参数列表的开始和结束
参数列表:(参数1,参数2,…,参数n):任何传入函数的参数和变量必须放在圆括号之间,用逗号分隔。函数从函数的调用这那里获取的信息
冒号:函数内容(封装的功能)以冒号开始,并且缩进
语句:函数封装的功能
return:一般用于结束函数,并返回信息给函数的调用者
表达式:即为要返回给函数的调用者的信息
注意:最后的return表达式,可以不写,相当于return None
二、最简单的函数(无参无返回值的函数)
假如我们在一个程序的很多地方都需要输出you reap what you sow,no pains no gains,You never know your luck三句话,可以把这三句话封装成一个函数,更加方便。
def myPrint():
print("you reap what you sow")
print("no pains no gains")
print("You never know your luck")
#这样一个函数就封装好了,只要我们在程序中调用myPrint,就能直接输出
#you reap what you sow
#no pains no gains
#You never know your luck
#调用函数
myPrint()
三、函数的参数
需求:编写一个函数,给函数一个字符串和一个数字,在函数内部打印出来
在编写这个函数之前,我们先来了解一下形参和实参。
形参(形式参数):定义函数时小括号中的变量,本质是变量。参数必须按顺序传递,个数目前来看要对应:形参有几个,实参就要写多少个。(当我们学习到到不定长参数就知道了)。
实参(实际参数):调用函数时给函数传递的数据,本质是值,不能是一个变量。
我们开始编写这个函数:
def myPrint(str, number):#调用时要传递的参数str和age
#这里的str和number就是形式参数
print(str, number)
myPrint("You never know your luck", 18)
#这里的字符串"You never know your luck"和数字18就是实际参数
#在调用过程中将实际参数传递给形式参数,即"You never know your luck"传递给str,将18传递给number
我其实我们想要实现这个功能可以直接print(“You never know your luck”, 18),那样写主要是为了大家可以理解在函数调用时实参传递给形参,并且实现功能的过程,哈哈哈大家不要在意。
四、函数的返回值
我们直接上例子来了解这个返回值。
编写函数,实现功能:给函数两个数,返回这两个数的和。
def mySum(num1, num2): #num1和num2是形式参数,将1和2分别代入计算
#将结果返回给函数的调用者
return num1 + num2 #返回num1和num2的和
#执行完return语句,该函数就结束了,return后面的代码不执行
print("hello") #不会执行
res = mySum(1, 2) #1和2是实际参数,传递给形式参数后执行1+2,然后将3返回给res
print(res) #输出:3
五、传递参数
参数的传递我们可以分为值传递和引用传递。
值传递:传递的是不可变类型,string、tuple、number是不可变的。
引用传递:传递的是可变类型,list、dice、set是可变的。
(一)值传递
def func1(num):
print(id(num)) #140707972736240
num = 10 #修改num的值不会改变,对外面的值是没有影响的
print(id(num)) #140707972735920 说明num = 10 是重新开辟出的一个内存空间
temp = 20
print(id(temp)) #140707972736240
func1(temp) #将temp的值传给形参num
print(id(temp)) #140707972736240
print(temp) #20
(二)引用传递
def func2(lis):
lis[0] = 100 #修改该函数对外面的值是有影响的
print(id(lis)) #1472735634056
li = [1,2,3,4,5]
print(id(li)) #1472735634056
func2(li)
print(li) #[100, 2, 3, 4, 5]
print(id(li)) #1472735634056
---------------------我是分割线---------------------------------
a = 10
b = 10
print(id(a), id(b))#140708061799344 140708061799344 地址相同
c = 20
d = 30
print(id(c), id(d))#140708061799664 140708061799984 地址不同
d = c
print(id(c), id(d))#140708061799664 140708061799664 地址相同
#但是
a = 10
b = 10
b = 40
print(id(a), id(b))#140708061799344 140708061800304 不一样了
六、关键字参数
概念:允许函数调用时参数的顺序与定义时不一致。
def myPrint(str, number):#调用时要传递的参数str和age
print(str, number)
#使用关键字参数
myPrint(age = 18, str = "You never know your luck")
七、默认参数
如果要用默认参数,最好将默认参数放到最后。
def myPrint(str = "You never know your luck", number= 18):
print(str, number)
myPrint("hello") #输出:hello 18
#只传递了一个字符串参数,number使用了默认值18
myPrint("hello",20) #输出:hello 20
#两个参数都传递了,使用传递的参数
八、不定长参数
概念:能处理比定义时更多的参数。
(一)加了一个星号(*)的参数
加了星号(*)的参数以元组(tuple)的形式导入,存放所有未命名的变量参数,如果在函数调用时没有指定参数,它就是一个空元组。
def func(name, *args):
print(name)
print(args)
for x in args:
print(x)
func("sunck", "good", "nice","handsome")
'''
输出:
You
('never', 'know', 'your', 'luck')
never
know
your
luck
'''
函数调用时没有指定星号(*)的参数。
def func(name, *args):
print(name)
print(args)
for x in args:
print(x)
func("luck")
'''
输出:
luck
()
什么都没有
'''
(二)加了两个星号(**)的参数
两个星号(**)的参数会以字典的形式导入,**代表键值对的参数字典,和*所代表的意义类似。
def func2(**kwargs):
print(kwargs)
print(type(kwargs))
func2(x=1, y=2, z=3)
'''
{'x': 1, 'y': 2, 'z': 3}
<class 'dict'>
'''
def func3(*args, **kwargs):
pass #表示一个空语句
#可以存放任意参数
九、匿名参数
概念:不使用def这样的语句定义函数,使用lamdba来创建匿名函数。
特点:1、lambda只是一个表达式,函数体比def简单。
2、lambda的主体是一个表达式,而不是代码块,仅仅只能在lambda表达式中封装简单的逻辑。
3、lambda函数有自己的命名空间,且不能访问自由参数列表之外的或全局命名空间的参数。
4、虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
格式:格式:lambda 参数1,参数2,…,参数n:expression
#一个简单的匿名函数
sum = lambda num1,num2:num1 + num2
print(sum(1,2))
#输出:3