2.7函数
2.7.1函数定义
对一段功能独立并且重复使用的代码进行封装,当我们需要使用的时候,在进行调用,目的是为了减少代码的重复性,提高代码的复用率
语法格式: def 函数名(形式参数名, 形式参数名1,...,形式参数名n): 函数功能体 return 返回值
解读:
-
def
关键字,用来定义函数的 -
函数名,根据功能自定义的名字,需要遵守标识符规则
-
() 存放函数的形式参数的,如果没有形式参数,()内为空
形式参数: 函数运算的时候 有些数据的未知[动态]的, 将这些未知的数据使用变量名来进行表示,这个变量名就是形式参数,简称形参。(实际参数见下)未知的数据有几个,就定义几个形式参数
-
return
,也是一个关键字,结束函数,并把结果返回到函数调用的位置如果功能需求中不需要返回值,可以写成
return None
或者省略注意:return和print不一样
-
print把数据输出到程序外的控制台
-
return把数据传递到函数调用的位置,数据还是在程序中运转的
-
定义函数的规则:
-
明确是否有未知项参与功能的运算 【用来定义形式参数有什么】
-
明确是否需要将结果返回到调用的位置 【决定return的情况】
eg: # 需求: 求圆的面积 S = π * r ** 2 # 公式中半径r是可以变化的 # 页面1. 求半径为3的圆的面积 圆周率定位3.14 area = 3.141592 * 3 ** 2 print(area) # 页面2. 求半径为1.5的圆的面积 圆周率定位3.14 area1 = 3.141592 * 1.5 ** 2 print(area1) # 页面3. 求半径为5的圆的面积 圆周率定位3.14 area2 = 3.141592 * 5 ** 2 print(area2) # 需求: 精确圆周率到小数点后6位 # 把功能封装成函数 def get_circle_area(radius): """ 求圆的面积 :param radius: 代表半径参与功能体的运算 称为形式参数 :return: 返回圆的面积 """ S = 3.141592 * radius ** 2 return S # 调用函数 res = get_circle_area(10) print('圆的面积是', res) # 调用函数 res1 = get_circle_area(17) print('圆的面积是', res1)
函数的调用
# 有返回值的函数调用 变量名 = 函数名(实际参数, 实际参数1, 实际参数2,..,实际参数n) # 没有返回值的函数调用 函数名(实际参数, 实际参数1, 实际参数2,..,实际参数n) """ 实际参数:实际参与函数功能运算的数据 称为实际参数,简称实参 实际参数的个数要和形式参数的个数一致,并且位置是一一对应的 定义函数的时候 函数内部的功能并未被执行,当调用的时候才会执行内部的功能 """
practice: 练习: 1. 求两个数中的最大值 未知项:有2个 是否返回结果: 需要 def get_max(a, b): return a if a > b else b # 三元函数 max_value = get_max(17, 20) print(max_value) 2. 对比两个数据的大小,前者大于后者返回1 前者等于后者返回0 前者小于后者返回-1 未知项:有2个 是否返回结果: 需要 def compare(a, b): return (a > b) - (a < b) # 调用函数 res = compare(17, 15) if res == 1: print('前者大于后者') elif res == 0: print('两者相等') else: print('前者小于后者') 或 def compare1(a, b): if a > b: print(1) elif a == b: print(0) else: print(-1) res1 = compare1(19, 18) print(res1) # None 3. 封装一个功能 打印NN乘法表 N为几 就打印几行乘法表 比如N为3 控制台打印为 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 未知项: 有1个 是否需要返回结果:不需要 def n_table(n): for r3 in range(1, n+1): # 行号 # 列的容器 for c3 in range(1, r3 + 1): # 列号 print(c3, '*', r3, '=', c3 * r3, end='\t') print() # 调用 n_table(5)
2.7.2函数的参数
位置参数
def add(a,b) 其中的a和b就是位置参数,也叫必须参数,调用函数的时候必须给这些参数赋值,赋值顺序和参数顺序一致且数量一致,不能少传或多传
默认参数
定义函数的时候,有些参数已经被赋予了数据值,这种参数就称为默认参数
特点: 不给它赋值,使用默认值参与运算,赋值的话使用新值参与运算
print()也是函数,不过不是我们自己定义的,而是系统环境中内置的函数 默认的 print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)里的value
应用场景:有些参数的值确实是不确定的,但大部分场景下的值是一样的【也就是大部分场景调用的时候传递的值是同一个】,为了简便调用,可以定义的时候,给这个参数设置一个默认值[大众场景下使用的数据]
eg: # 默认参数 # 定义一个函数 求x的y次方 def power(x, y=2): # 给y设置默认值为2,赋值的时候赋x的值即可 return x ** y res = power(3) print(res) res = power(9) print(res) # 其他的场景可以给y再次赋值,赋值时赋x,y的值 # 求10的三次方 res = power(10, 3) print(res) # 注意,默认参数定义的位置必须在位置参数之后
注意,默认参数定义的位置必须在位置参数之后
关键字参数
针对调用的时候(不是定义的时候),传递的实参格式可以写成:形参名=实参值, 这种格式称为关键字参数
关键字参数在进行传值的时候,顺序可以发生变化【本质上再给变量名进行赋值,找到匹配的变量名进行相应的赋值】
eg: # 获取某个月的天数 # 未知的数据有几个:2个,年和月 # 返回值:返回天数 def get_days(year,month) if month not in range(1,13): raise ValueError('data value not in 1-12') #可以手动设置报错 # 元组类型 使用()包含多个数据的容器 # in 是成员运算符 如果月份是列出来的数据其中一个 if month in (1, 3, 5, 7, 8, 10, 12): return 31 elif month in (4, 6, 9, 11): return 30 else: if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0) # 先判断月,再考虑与年有关的2月分,可以简化代码 return 29 else: return 28 print(get_days(2022,2)) # 参数不按顺序赋予的话,比如说参数特别多,可以应用关键字参数传值,顺序可以发生变化 print(get_days(year=2022,month=2)) 或者 print(get_days(month=2,year=2022)) # 但是位置参数不可以改变顺序
tips:手动设置报错:raise ValueError('data value not in 1-12')
可变参数
定义**函数的时候,需要按照需求分析未知项的个数,来确定形参的个数,但是有些场景格式无法确定的,比如封装一个函数:求多个数据的和,像这种形式参数个数不能确定的使用可变参数,可变参数有两种格式:
-
*args
【args
就是一个变量,可以定义成其他名字】应用于多个位置参数的传值
-
**kwargs
【kwargs
也是一个变量,可以定义成其他名字】应用于多个关键字参数
形参名=数据值
的传值
# 之前在print()里接触过,print(*args)决定了print可以一次性打印多个数据 eg: # 计算几个数据的和: def get_sum(*nums): # 当使用*来标记nums的时候 nums就变成了一个容器型数据 # 因为需要接受多个数据,索引接受的变量需要是一个容器类型的 print(nums, type(nums)) # (1, 2, 3) <class 'tuple'> 小括号包含着多个数据 类型元组类型的 total = 0 # 记录累加和 for ele in nums: total += ele return total # 调用函数 print(get_sum(1, 2, 3)) get_sum(1)
""" 注册的时候有必填项和选填项 必填项:用户名 密码 选填项:性别 出生日期 籍贯 流程: 在网站上注册的时候 填的信息 网站的服务器要对这些信息进行存储 网站要对用户的信息进行保存 必填项代表的是 必须传递的数据 【使用函数中的位置参数来表示】 选填项 可以填也可以不填 填1个 也可以填多个 个数就不确定了 【填的信息也不确定】 【使用可变参数来表示】 为了明确传递的是性别 还是出生日期 还是籍贯 使用关键字形式传值 进行标记 """ def register(username, password, **kwargs): # {} 代表的是字典类型的容器,对每个数据都有标记 数据格式是{key:value},value就是数据值 key就是数据的标记 可以通过key标记获取到对应的数据值 print('填充的信息有', username, password, kwargs) # 如何根据标记名获取值 kwargs.get(key) # 在kwargs中获取key对应的数据值 【key是实际的标记名称】 # 如果有相应的信息 返回对应的数据,没有的话返回空值 print(kwargs.get('出生日期')) register('admin', '123456') # 关键字参数传值 格式 变量名=实参值 register('admin', '123456', 性别='女', 出生日期='2000-11-10') # 填充的信息有 admin 123456 {'性别': '女', '出生日期': '2000-11-10'} # 变量名可以定义成汉字,在这里汉字也算字母的一种 =============================================================== # 命名关键字参数 # 涉及到一个符号 * # 定义函数的时候,*后面的参数必须以关键字格式传值,如下: def register1(*, username, password): print(username, password) register1('admin', '123456')# 如果这样输入就会报错↓ # 报错,错误原因:register1中有0个位置参数,但是输入了两个,TypeError: register1() takes 0 positional arguments but 2 were given register1(username='admin', password='123456') # 正确输入方法 # pymysql.Connection
tips:命名关键字参数符号*,其后面的参数必须以关键字格式传递xxx='xxxx'