Python 基础
第五章 函数
一、定义
- 用于封装一个特定的功能,表示一个功能或者行为。
- 函数是可以重复执行的语句块, 可以重复调用。
二、作用
- 提高代码的可重用性和可维护性(代码层次结构更清晰)。
三、定义函数
- 语法:
def 函数名(形式参数): 函数体
- 说明:
def 关键字:全称是define,意为”定义”。
函数名:对函数体中语句的描述,规则与变量名相同。
形式参数:方法定义者要求调用者提供的信息。
函数体:完成该功能的语句。 - 函数的第一行语句建议使用文档字符串描述函数的功能与参数。
四、调用函数
- 语法:函数名(实际参数)
- 说明:根据形参传递内容。
五、返回值
- 定义:
方法定义者告诉调用者的结果。 - 语法:
return 数据 - 说明:
return后没有语句,相当于返回 None。
函数体没有return,相当于返回None。
六、可变/不可变类型在传参时的区别
- 不可变类型参数有:
数值型(整数,浮点数,复数)
布尔值bool
None 空值
字符串str
元组tuple
固定集合frozenset - 可变类型参数有:
列表 list
字典 dict
集合 set - 传参说明:
不可变类型的数据传参时,函数内部不会改变原数据的值。
可变类型的数据传参时,函数内部可以改变原数据。
"""
函数-参数
练习:exercise01
"""
def attack():
"""
攻击函数
"""
print("侧踹")
print("直拳")
print("摆拳")
print("勾拳")
print("肘击")
# attack()
# ...
attack()
# 有参数函数
# 形式参数
def attack_repeat(count):
"""
重复攻击
:param count:int类型,重复的次数
"""
for i in range(count):
print("侧踹")
print("直拳")
print("摆拳")
print("勾拳")
print("肘击")
# 实际参数
attack_repeat(3)
"""
print("直拳")
print("摆拳")
print("勾拳")
print("肘击")
#.......
print("直拳")
print("摆拳")
print("勾拳")
print("肘击")
#.......
print("直拳")
print("摆拳")
print("勾拳")
print("肘击")
"""
"""
将下列代码,定义到函数中,打印矩形。
for r in range(3):
for c in range(5):
print("*", end=" ")
print()
"""
def print_rectangle(r_count,c_count,char):
for r in range(r_count):
for c in range(c_count):
print(char, end=" ")
print()
print_rectangle(5,3,"*")
print_rectangle(2,7,"#")
"""
函数-返回值
"""
def fun01():
print("fun01执行喽")
return 100 # 返回100
number = fun01()
print(number)
def fun02():
print("fun01执行喽")
# return # return关键字后面如果没有数据,相当于返回None
# 如果函数没有返回值,也相当于返回None
re = fun02()
print(re)
# 即使有返回值,调用者仍然可以不使用变量来接受。
fun01()
"""
函数-应用
"""
# 函数:封装一个特定功能,表示一个行为。
# 小而精
# 两个数值相加功能
# def add():
# number_one = float(input("请输入第一个数据:"))
# number_two = float(input("请输入第二个数据:"))
# result = number_one + number_two
# print("结果是:" + str(result))
#
# add()
def add(number_one, number_two):
return number_one + number_two
result = add(5, 2)
"""
定义函数,计算多位整数每位相加和.
输入:12345
输出:15
"""
def each_unit_sum(number):
"""
计算整数的每位相加和
:param number:需要操作的数据,int类型
:return:相加的结果,int类型
"""
sum_value = 0
for item in str(number):
sum_value += int(item)
return sum_value
re = each_unit_sum(12345)
print(re)
"""
定义函数,根据成绩计算等级。
输入:96
输出:优秀
"""
# def get_score_level(score):
# if score < 0 or score > 100:
# return "成绩输入有误"
# elif 90 <= score:
# return "优秀"
# elif 80 <= score:
# return "良好"
# elif 60 <= score:
# return "及格"
# else:
# return "不及格"
def get_score_level(score):
if score < 0 or score > 100:
return "成绩输入有误"
if 90 <= score:
return "优秀"
if 80 <= score:
return "良好"
if 60 <= score:
return "及格"
return "不及格"
print(get_score_level(95))
"""
定义函数,判断列表中是否存在相同元素
输入:[3,4,6,8,6]
输出:True
"""
def is_repeating(list_target):
for r in range(len(list_target) - 1):
for c in range(r + 1, len(list_target)):
if list_target[r] == list_target[c]:
return True
return False
list01 = [3,4,6,8,7]
print(is_repeating(list01))
"""
函数内存分配
"""
# 将函数的代码,存储到代码区,函数体中的代码不执行。
def fun01():
a = 100
# 调用函数时,在内存中开辟空间,存储函数内部定义的变量,该空间叫做栈帧。
# 函数执行过后,栈帧释放。
fun01()
def fun02(p1,p2):
p1 = 20
p2[0] = 20
# 结论1:传入不可变对象,函数体内部不可能修改数据
a = 10
# 结论2:传入可变对象,函数体内部可能修改数据
b = [10]
fun02(a,b)
print(a)#?
print(b)#?20
def fun03(p1,p2):
p1[0] = 20
p2 = 20
a = [10]
b = [10]
fun02(a,b)
print(a)#?
print(b)#?
"""
定义方阵转置函数
for c in range(len(list01)-1):
for r in range(c+1, len(list01)):
list01[r][c],list01[c][r] = list01[c][r] ,list01[r][c]
"""
# def square_matrix_tranpose(matrix):
# for c in range(len(matrix) - 1):
# for r in range(c + 1, len(matrix)):
# matrix[r][c], matrix[c][r] = matrix[c][r], matrix[r][c]
# return matrix
#
# list01 = [
# [1,2,3,4],
# [5,6,7,8],
# [9,10,11,12],
# [13,14,15,16],
# ]
# print(square_matrix_tranpose(list01))
def square_matrix_tranpose(matrix):
for c in range(len(matrix) - 1):
for r in range(c + 1, len(matrix)):
matrix[r][c], matrix[c][r] = matrix[c][r], matrix[r][c]
list01 = [
[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16],
]
square_matrix_tranpose(list01)
print(list01)
七、变量作用域
- 作用域:变量起作用的范围。
- Local局部作用域:函数内部。
- Enclosing 外部嵌套作用域 :函数嵌套。
- Global全局作用域:模块(.py文件)内部。
- Builtin内置模块作用域:builtins.py文件。
1. 变量名的查找规则
- 由内到外:L -> E -> G -> B
- 在访问变量时,先查找本地变量,然后是包裹此函数外部的函数内部的变量,之后是全局变量,最后是内置变量。
2. 局部变量
- 定义在函数内部的变量(形参也是局部变量)
- 只能在函数内部使用
- 调用函数时才被创建,函数结束后自动销毁
3. 全局变量
- 定义在函数外部,模块内部的变量。
- 在整个模块(py文件)范围内访问(但函数内不能将其直接赋值)。
4. global 语句
- 作用:
在函数内部修改全局变量。
在函数内部定义全局变量(全局声明)。 - 语法:
global 变量1, 变量2, … - 说明
在函数内直接为全局变量赋值,视为创建新的局部变量。
不能先声明局部的变量,再用global声明为全局变量。
5. nonlocal 语句
- 作用:
在内层函数修改外层嵌套函数内的变量 - 语法
nonlocal 变量名1,变量名2, … - 说明
在被嵌套的内函数中进行使用
"""
变量作用域
"""
# 全局作用域:整个.py文件
# 全局变量
g01 = 100
def fun01():
# 局部作用域:函数的内部
# 局部变量
a = 10
print(a)
# 可以在局部作用域中,读取全局变量。
# print(g01)
# 实际创建了局部变量,没有改变全局变量。
# g01 = 200
# 声明全局变量
global g01
g01 = 200
# global g02
# g02 = 500
fun01()
print(g01)
# print(g02)
八、函数参数
1. 实参传递方式argument
1.1 位置传参
- 定义:实参与形参的位置依次对应。
1.2 序列传参
- 定义:实参用*将序列拆解后与形参的位置依次对应。
1.3 关键字传参
- 定义:实参根据形参的名字进行对应。
1.4 字典关键字传参
- 定义:实参用**将字典拆解后与形参的名字进行对应。
- 作用:配合形参的缺省参数,可以使调用者随意传参。
2. 形参定义方式parameter
1. 缺省参数
- 语法:
def 函数名(形参名1=默认实参1, 形参名2=默认实参2, ...):
函数体
- 说明:
- 缺省参数必须自右至左依次存在,如果一个参数有缺省参数,则其右侧的所有参数都必须有缺省参数。
- 缺省参数可以有0个或多个,甚至全部都有缺省参数。
2. 位置形参
- 语法:
def 函数名(形参名1, 形参名2, ...):
函数体
3. 星号元组形参
- 语法:
def 函数名(*元组形参名):
函数体
- 作用:
- 收集多余的位置传参。
- 说明:
- 一般命名为’args’
- 形参列表中最多只能有一个
4. 命名关键字形参
- 语法:
def 函数名(*, 命名关键字形参1, 命名关键字形参2, ...):
函数体
def 函数名(*args, 命名关键字形参1, 命名关键字形参2, ...):
函数体
- 作用:
- 强制实参使用关键字传参
5. 双星号字典形参
- 语法:
def 函数名(**字典形参名):
函数体
- 作用:
- 收集多余的关键字传参
- 说明:
- 一般命名为’kwargs’
- 形参列表中最多只能有一个
3. 参数自左至右的顺序
- 位置形参 --> 星号元组形参 --> 命名关键字形参 --> 双星号字典形参
"""
函数参数
实际参数
"""
def fun01(a, b, c):
print(a)
print(b)
print(c)
# 1. 位置实参:根据位置,将实参传递给形参。
fun01(1, 2, 3)
# 2.序列实参:使用星号将序列拆分后,与形参进行对应。
list01 = [4, 5, 6]
fun01(*list01)
# 3.关键字:根据名称,将实参传递给形参。
fun01(a=1, c=3, b=2)
# 4. 字典实参:使用双星号将字典拆分后,与形参进行对应。
dict01 = {"c": 3, "b": 2, "a": 1}
fun01(**dict01)
"""
函数参数
实际参数
位置实参
序列实参
关键字实参
字典实参
形式参数
默认形参
位置形参
星号元组形参
命名关键字形参
双星号字典形参
"""
# 1. 位置形参:约束实参必须提供 【必填】
def fun01(a, b, c):
print(a)
print(b)
print(c)
# 2. 默认参数:实参可以不提供 【可选】
def fun02(a=0, b="", c=0.0):
print(a)
print(b)
print(c)
fun02(1)
fun02(b="bb")
# 3. 星号元组形参:将位置实参合并为一个元组
# 只能有一个,建议形参名称位args
def fun03(*args):
print(args)
fun03(1, 2, 3)
# fun03(a = 1,b=2)
# 4. 命名关键字形参:星号元组形参,后面的位置形参,必须使用关键字实参传递。
def fun04(*args, a, b, c):
print(args)
fun04(1, 2, 3, 4, 5, a=1, b=2, c=3)
# 命名关键字形参:星号后面的位置形参,必须使用关键字实参传递。
def fun05(a, *, b=0, c=0):
print(a)
print(b)
print(c)
fun05(1, c=3)
# print(*args, sep=' ', end='\n')
print(1, 2, 3, 4, end=" ")
print(1, 2, 3, 4, sep="-")
print(1, 2, 3, 4, end=" ", sep="-")
# 5. 双星号字典形参:将关键字实参合并为一个字典
# 只能有一个,建议形参名称位args
def fun06(**kwargs):
print(kwargs)
fun06(a = 1,b = 2)
"""
定义函数计数器,统计函数被调用的次数。
"""
count = 0
def fun01():
global count
count += 1
fun01()
fun01()
fun01()
print("执行次数是:" + str(count))
"""
定义函数,根据小时、分钟、秒计算总秒数。
要求:
根据小时、分钟、秒
根据小时、分钟
根据分钟、秒
根据分钟
"""
def get_total_second(hour=0, minute=0, second=0):
return hour * 3600 + minute * 60 + second
print(get_total_second(1, 2, 3))
print(get_total_second(1, 2))
print(get_total_second(minute=2, second=3))
print(get_total_second(minute=2))
"""
定义函数,多个数值累加.
"""
def sum(*args):
sum_value = 0
for item in args:
sum_value += item
return sum_value
print(sum(213,3,4,3,5,6,67))
print(sum())
# def sum(args):
# sum_value = 0
# for item in args:
# sum_value += item
# return sum_value
#
# print(sum([213,3,4,3,5,6,67]))
# print(sum([]))
4. 强化
"""
调用下列函数
"""
def fun01(*args, **kwargs):
print(args)
print(kwargs)
fun01()
fun01(12,2,a = 1,b=2)
# fun01(12,a = 1,2,b=2)
def fun02(a, *args, b, c="", **kwargs):
print(a)
print(args)
print(b)
print(c)
print(kwargs)
fun02(1,2,3,b = 2,c="3",d = 4)
fun02(a = 1,b = 2)
"""
对字符串:" 自强不 息, 厚德 载物. "
查找空格数量
删除所有空格
查找"厚德"位置
判断是否以"自强"开头
"""
message = " 自强不 息, 厚德 载物. "
print(message.count(" "))
print(message.replace(" ",""))
print(message.find("厚德"))
print(message.startswith("自强"))
5. 总结
- 实际参数:调用函数
- 位置实参:根据位置与形参对应
- 序列实参:拆分序列后根据位置与形参对应
- 关键字实参:根据名称与形参对应
- 字典实参:拆分字典后根据名称与形参对应
- 位置实参:根据位置与形参对应
- 形式参数:定义函数
- 缺省参数:实参可以不提供
- 位置形参:实参必须提供
- 星号元组形参:将位置实参合并为元组,位置实参数量无限
- 命名关键字形参:约束实参必须使用关键字实参
- 双星号字典形参:将关键字实参合并为字典,关键字实参数量无限
九、重构
- 购物
# 重构:结构清晰,主题鲜明。
# 实现细节 --> 执行过程
# shift + F6 一键修改变量名
# ctrl+alt+m 提取函数
dict_commodity_info = {
101: {"name": "屠龙刀", "price": 10000},
102: {"name": "倚天剑", "price": 10000},
103: {"name": "九阴白骨爪", "price": 8000},
104: {"name": "九阳神功", "price": 9000},
105: {"name": "降龙十八掌", "price": 8000},
106: {"name": "乾坤大挪移", "price": 10000}
}
list_order = []
def buying():
"""
购买
"""
print_commdity_info()
dict_order = create_order()
list_order.append(dict_order)
print("添加到购物车。")
def create_order():
"""
创建订单
:return: 字典类型的订单对象
"""
while True:
cid = int(input("请输入商品编号:"))
if cid in dict_commodity_info:
break
else:
print("该商品不存在")
count = int(input("请输入购买数量:"))
return {"cid": cid, "count": count}
def print_commdity_info():
for key, value in dict_commodity_info.items():
print("编号:%d,名称:%s,单价:%d。" % (key, value["name"], value["price"]))
def shopping():
"""
购物
"""
while True:
item = input("1键购买,2键结算。")
if item == "1":
buying()
elif item == "2":
settlement()
def settlement():
"""
结算
"""
total_price = calculate_total_price()
print_order_into()
paying(total_price)
def paying(total_price):
"""
支付
:param total_price:数值类型的总价
"""
while True:
money = float(input("总价%d元,请输入金额:" % total_price))
if money >= total_price:
print("购买成功,找回:%d元。" % (money - total_price))
list_order.clear()
break
else:
print("金额不足.")
def print_order_into():
for order in list_order:
dict_commodity = dict_commodity_info[order["cid"]]
print("商品:%s,单价:%d,数量:%d." % (dict_commodity["name"], dict_commodity["price"], order["count"]))
def calculate_total_price():
"""
计算总价
:return: 数值类型的总价格
"""
total_price = 0
for order in list_order:
dict_commodity = dict_commodity_info[order["cid"]]
total_price += dict_commodity["price"] * order["count"]
return total_price
shopping()