函数存在的价值:当一个功能需要反复使用的时候,如果没有函数,每次需要这个功能就必须把实现这个功能的代码写一遍。如果有函数,实现功能对应的代码只需要写一遍,然后每次需要这个功能的时候调用实现这个功能的函数。
什么是函数
函数是实现某一特定功能的代码的封装。(函数就是将实现某一个或者某类功能的代码打成一个包,以后在需要这包中的这段代码对应的功能的时候不用重新写这段代码,而是使用封装了这段代码的函数)
函数的分类
根据函数是由谁创建的,将函数分为系统函数和自定义函数两种。
1)系统函数(别以及造好的机器)
由系统创建的函数(python本身就创建好的函数),例如:print、input、type、max、min等。
2)自定义函数(自己造的机器)
由程序员自己创建的函数。
定义函数(造机器)
语法🌸:
def 函数名(形参列表):
函数说明文档
函数体
结构说明:
结构 | 说明 |
---|---|
def | 关键字;固定写法 |
函数名 | 由程序员自己命名。两个要求:是标识符;不是关键字。三个规范:见名知义(看到函数名就大概知道函数的功能是什么);所有的字母都小写,多个单词用下划线隔开;不使用系统的函数名、类名和模块名 |
(): | 固定写法 |
形参列表 | 以’变量名1,变量名2,变量名3,…'的形式存在,根据情况变量的数量可以为0(每一个变量就是一个形参)。形参的作用:将函数外部的数据传递到函数里面。确定形参的方法:看实现的功能需不需要额外的数据,需要多少个额外的数据。 |
函数说明文档 | 多行注释(相当于生活中机器的说明书) |
函数体 | 结构上,和def保持一个缩进的一条或者多条语句。逻辑上,函数体就是实现函数功能的代码。 |
🌰定义一个函数求一个数的阶乘
def factorical(n):
"""
(功能说明区)求一个数的阶乘:num!
:param n: (参数说明区)求阶乘的对象
:return:(返回值说明)None
"""
fac = 1
for i in range(1, n + 1):
fac *= i
print(fac)
factorical(5) #120
def product(a, b):
print(a * b)
product(3, 4) #12
🌰练习1:定义一个函数统计字符串中数字字符的个数
def count_nums(str1):
"""
计字符串中数字字符的个数
:param str1: 指定的字符串对象
:return: None
"""
count1 = 0
for i in str1:
if i.isdigit():
count1 += 1
print(count1)
count_nums('y76r3rour') #3
🌰练习2:定义一个函数,将两个字符串中所有的大写字母合并成一个新的字符串
def combine(str1, str2):
str3 = ''
for i in str1 + str2:
if i.isupper():
str3 += i
print(str3)
combine('qhurnyiceGG', 'jnjdJBGUVKNKNm') #GGJBGUVKNKN
🌰练习3:定义一个函数,删除列表中所有的空值(包括None,和其他空值(比如空字符串、空列表、空元组等))
#方法一
def delete(list1):
for i in list1[:]:
if i == '' or i == [] or i == () or i == None:
list1.remove(i)
print(list1)
#方法二
def delete(list1):
for i in list1[:]:
# if bool(i) == False and i != 0:
if (not i) and (i != 0):
list1.remove(i)
print(list1)
delete([None, 1, 2, 4, [], '', 2, [], (1, 2), ()]) #[1, 2, 4, 2, (1, 2)]
条件对应的表达式如果不是布尔,就转换成布尔看结果是否为True(0值和空值是False,其他都是True)
调用函数(使用函数-使用机器)
语法🌸:
函数名(实参列表)
结构说明:
结构 | 说明 |
---|---|
函数名 | 需要哪个函数对应的功能,就调用哪个函数;想要调用哪个函数就写哪个函数的函数名。注意:函数名必须是已经定义过的函数名。 |
() | 固定写法 |
实参列表 | 以’数据1,数据2,数据3,…'的形式存在,这儿的每一个数据就是一个实参。(实参对应的数据可以是任何结果的表达式)。实参是用来给形参赋值的,在提供实参的时候要保证和形参一一对应。 |
变量名1,变量名2,变量名3,…=数据1,数据2,数据3,… 形参=实参
重要结论:定义函数不会执行函数体,调用函数的时候才会执行函数体
函数调用过程
每次在调用的时候,它的执行步骤:
Step1:回到函数定义的位置
Step2:传参(用实参给形参赋值,传参的时候必须保证每个形参都有值)
Step3:执行函数体
Step4:确定函数返回值
Step5:回到函数调用的位置,接着往后执行
关于形参几种错误的写法
1)错误写法1:将实参写在函数的外部
str1='y76r3rour'
def count_nums():
count1 = 0
for i in str1:
if i.isdigit():
count1 += 1
print(count1)
count_nums()
2)错误写法2:将实参写在函数内部,以后将只针对于这一个字符串。
def count_nums():
str1 = 'y76r3rour'
count1 = 0
for i in str1:
if i.isdigit():
count1 += 1
print(count1)
count_nums()
位置参数和关键字参数
根据实参的提高方式,将实参分为位置参数和关键字参数。
1)位置参数:以’实参1,实参2,实参3,…'的形式存在,让实参和形参从位置上一一对应。
def fun1(x,y,z):
print(f'x:{x},y:{y},z:{z}')
fun1(100,2003,21) #x:100,y:2003,z:21
2)关键字参数:以’形参1=实参1,形参2=实参2,…‘的形式存在,通过’='将实参和形参对应。
def fun1(x,y,z):
print(f'x:{x},y:{y},z:{z}')
fun1(x=100,y=23,z=34) #x:100,y:23,z:34
注意:位置参数和关键字参数可以一起用,但是必须保证位置参数在关键字参数的前面。
func1(10,y=20,z=33) #x:10,y:20,z:33
func1(x=10,20,z=33) #报错!
参数默认值
定义函数的时候可以通过’形参名=数据’的方式,给形参赋默认值;
在调用函数的时候,有默认值的参数可以不用传参。
如果想跳过前面有默认值的参数,直接给后面的参数赋值,使用关键字参数传参。
注意:定义函数的时候,如果一个函数有的参数有默认值,有的参数没有默认值,那么没有默认值的形参必须在默认值参数的前面。
def fun2(x=1, y=2, z=3):
print(f'x:{x},y:{y},z:{z}')
#不传参
fun2() #x:1,y:2,z:3
#传一个值
fun2(100) #x:100,y:2,z:3
fun2(100, 9) #x:100,y:9,z:3
fun2(100, 9, 29) #x:100,y:9,z:29
fun2(z=78) #x:1,y:2,z:78
参数类型说明
没有默认值参数的类型说明:直接在形参后面加’:类型名’;
有默认值的参数,默认值数据对应的类型就是这个形参的类型。
def fun3(x: str, y=''):
x.isdigit()
fun3()
*对应的不定长参数
1)参数个数不确定,可以使用不定长参数
定义函数的时候,如果在某一个形参前面加*,那么这个形参就会变成一个不定长参数,它可以接收多个实参(可以是0——无穷个)
带*的不定长参数的本质是一个元组,它接收到的实参是这个元组中的元素。
def sumN(*nums):
sum1 = 0
for i in nums:
sum1 += i
print(sum1)
#优化:求和的时候至少两个参数
def sumN1(num1, num2, *nums):
sum1 = num1 + num2
for i in nums:
sum1 += i
print(sum1)
sumN()
sumN(1)
sumN(1,2)
2)定义函数的时候,单独使用*
如果定义函数的时候,形参列表中有一个独立的*,调用函数的时候 *后面的所有形参必须使用关键字参数传参。
def func4(x, *, y, z):
pass
def func5(*, y, z):
pass
#最后两个值必须使用关键字参数传参,不然会报错!
def func6(x, *y, z, t):
pass
func6(1, 2, 3, 4, 5, z=1, t=2)