python 第六课 (字典 函数 None 作用域 函数嵌套 函数递归调用 重点)
字典的基本特性
1.字典(dict)是Python中用于存储键值对(key-value)的数据结构
2.键必须是不可变类型(如数字、字符串、元组
3.值可以是任意类型。字典是可变的,支持动态增删改查操作。
4.字典可以嵌套, 都可以嵌套
字典的定义方式
空字典可以通过花括号{}或dict()函数创建:
d1={}d2=dict()带初始值的字典直接使用花括号声明键值对:
d3={'张三':18,'李四':19}d4={100:150,'李四':30}键的注意事项
1.字典的键必须是不可变类型,若使用可变类型(如列表)会报错。
2.修正方法是将可变类型转换为不可变类型(如元组):
# 错误示例:列表作为键d5={['抽烟','喝酒']:70}# 正确示例:元组作为键d6={('抽烟','喝酒'):70}值的灵活性
字典的值可以是任意类型,包括列表、嵌套字典等:
d7={'数据计算':['武惠强','白洁']}# 值为列表键重复的处理
当键重复时,后定义的键值会覆盖先前的值:
d8={'王五':'赵六','李四':30,'王五':'赵六'}# 若后续出现相同键,值会被覆盖类型检查
使用type()函数可验证字典类型:
print(type(d1))# 输出:<class 'dict'>字典基本操作总结
字典添加
通过直接赋值或update()方法添加键值对:
stu={"name":"武惠强",'age':18,"height":176.5}stu['hobby']=['抽烟','喝酒','烫头']# 直接添加stu.update({'name':'嘉禾'})# 通过update合并字典运行结果:{'name':'武惠强','age':18,'height':176.5,'hobby':['抽烟','喝酒','烫头']}{'name':'嘉禾','age':19,'height':176.5}字典删除
使用del、pop()或clear()方法:
delstu["hobby"]# 删除指定键值对res=stu.pop('weight')# 删除并返回valueres2=stu.pop('id','删除失败')# 安全删除(避免报错)stu.clear()# 清空字典运行结果:160删除失败{}字典修改
直接赋值或通过update()更新:
stu['age']=19# 直接修改stu.update({'name':'嘉禾'})# 批量更新运行结果:{'age':19}{'age':19,'name':'嘉禾'}字典查询
通过键访问或get()方法:
res4=stu['name']# 直接访问(键不存在时报错)res5=stu.get('hobby','meiyo')# 安全访问(返回默认值)运行结果: meiyo 嘉禾遍历字典
获取键、值或键值对:
keys=stu.keys()# 获取所有键(dict_keys类型)values=stu.values()# 获取所有值(dict_values类型)items=stu.items()# 获取键值对(dict_items类型)forkeyinstu:# 遍历键并访问值print(key,stu[key])运行结果: dict_keys(['name','age','height'])dict_values(['嘉禾',19,176.5])dict_items([('name','嘉禾'),('age',19),('height',176.5)])name 嘉禾 age19height176.5注意事项
- 1.直接通过键访问(如
stu['key'])在键不存在时会报错,推荐使用get()方法。 2.pop()可设置默认值避免报错,del无法提供默认值。3.update()可批量更新或添加键值对,适合合并字典。
函数的定义与作用
函数是用于执行特定任务的重复使用代码块,主要作用包括:
- 代码复用,减少重复编写相同逻辑
- 提升程序可读性和维护性
- 支持模块化开发,便于团队协作
函数的分类
- 内置函数:如
print()、type()、range(),无需导入即可直接使用 - 模块函数:需导入模块后调用,例如
random.randint()、math.sqrt() - 自定义函数:由开发者定义,通过
def关键字声明,例如:
def函数名(形参):函数体形参与实参的区别
- 形参:函数定义时声明的参数,用于接收外部传入的值,作用域仅限于函数内部
- 实参:调用函数时传递的具体值或变量
示例说明
无参函数:
defwelcome():print('欢迎大家来到')welcome()# 多次调用避免重复代码带参函数:
deforder(num,dish):print(f'你点了{num}号{dish}')order(7,"桃花面")# 实参为具体值函数返回值:
通过return返回结果,例如实现冒泡排序:
defbubbleSort(arr):foriinarr:forjinrange(len(arr)-1):ifarr[j]>arr[j+1]:arr[j],arr[j+1]=arr[j+1],arr[j]returnarr sorted_arr=bubbleSort([10,1,5,6,4])print(sorted_arr)位置参数
函数调用时,参数按定义顺序传递,实参与形参一一对应。例如:
order(7,"桃花面")# 7对应num,"桃花面"对应dish关键字参数
通过形参名直接指定实参,允许参数顺序与定义不一致。例如:
info(height=170,name='张强',gender="男",age=18)混合使用规则
位置参数必须出现在关键字参数之前。例如:
info('董小姐',18,height=175,gender='女')参数传递限制
/前的参数必须用位置参数传递*后的参数必须用关键字参数传递/必须位于*之前。例如:
definfor(name,/,age,*,gender,height):print(f"我是{name},我今年{age}岁,我是{gender}生,我的升高是{height}")infor('sb',18,height=175,gender='女')默认参数
形参可设置默认值,调用时未传递则使用默认值。例如:
definfor2(name,/,age,*,gender,height,msg='默认消息'):...infor2('sb',18,height=175,gender='女')# 使用默认msg可变位置参数(*args)的特点
调用函数时,所有未命名的位置参数会被收集到一个元组中,通过args访问。test1('张强',18,'男',170)的输出显示args是一个包含所有额外位置参数的元组。
可变关键字参数(**kwargs)的特点
调用函数时,所有未命名的关键字参数会被收集到一个字典中,通过kwargs访问。test2(name='阿涛',age=20,height=170)的输出显示kwargs是一个包含所有额外关键字参数的字典。
参数顺序的注意事项
当函数定义中包含位置参数、默认参数、可变位置参数和可变关键字参数时,必须严格按照以下顺序声明:
- 普通位置参数(如
a,b) - 默认参数(如
c='我是') - 可变位置参数(
*args) - 可变关键字参数(
**kwargs)
默认参数的位置影响
当默认参数放在可变位置参数之前(如def test3(a,b,c='我是',*args,**kwargs)),调用时'chou'会被赋值给c,后续参数进入args元组。
当默认参数放在可变位置参数之后(如def test3(a,b,*args,c='我是',**kwargs)),必须通过关键字显式指定c的值,否则会被args捕获。
代码执行结果差异
第一种定义方式下test3('张三','娜','chou','hejiu','tangtou',age='18')会将'chou'作为默认参数c的值。
第二种定义方式下相同调用会将'chou'作为args的一部分,而c保持默认值'我是'。
None 的特性总结
None 是 Python 中表示空值或无意义的特殊常量,属于NoneType类型。
在条件判断中,None 会被视为False。
None 不能参与数学运算或字符串拼接操作。
函数默认返回值为 None,除非显式使用return指定返回值。
空值与 False 的等价性示例
以下值在条件判断中会被视为False:
- 空字符串
'' - 数字
0 - 布尔值
False - 空列表
[] None
函数返回值规则
函数若不设置return语句,默认返回None。
使用return时:
return后的表达式作为函数返回值return会立即终止函数执行,后续代码不再运行
示例:
defadd(a,b):returna+b# 返回两数之和result=add(10,20)# 结果为30作用域的定义与分类
作用域指变量在程序中可被访问的范围,分为全局作用域和局部作用域。
1.全局作用域变量在整个程序中有效。
2.局部作用域变量仅在函数或代码块内有效。
全局作用域与局部作用域的特点
全局变量
a=100b=200deftest():# 局部变量c='你好'd='python'# 声明使用全局变量aglobala# 修改全局变量a的值a=30# 函数内打印变量print('函数a:',a)# 输出:函数a: 30print('函数b:',b)# 输出:函数b: 200(访问全局变量b)print('函数c:',c)# 输出:函数c: 你好(访问局部变量c)print('函数d:',d)# 输出:函数d: python(访问局部变量d)# 调用函数test()# 全局作用域打印变量print('全局打印a',a)# 输出:全局打印a 30(已被函数修改)print('全局打印b',b)# 输出:全局打印b 200# print(c) # 这行会报错:NameError: name 'c' is not defined(c是函数内局部变量,外部无法访问)- 定义在函数外部,整个程序均可访问。
- 生命周期从程序开始到结束。
- 示例:
a = 100,b = 200。
局部变量
- 定义在函数内部,仅函数内可访问。
- 生命周期从函数调用开始到函数执行结束。
- 示例:
c = '你好',d = 'python'。
使用global关键字
通过global可将局部变量声明为全局变量,或在函数内修改全局变量:
globala# 声明使用全局变量aa=30# 修改全局变量a的值作用域的生命周期
- 局部变量:函数调用时创建,执行完毕后销毁。多次调用函数时,每次都会重新创建局部变量(如
m在test3()中每次初始化为100)。
deftest3():m=100m+=1print(f'我是函数中的m为{m}')test3()test3()test3()test3()运行结果为: 我是函数中的m为101我是函数中的m为101我是函数中的m为101我是函数中的m为101- 全局变量:程序启动时创建,结束时销毁。函数内修改后全局生效(如
y通过global声明后累加)。
y=100deftest3():globaly y+=1print(f'我是函数中的y为{y}')test3()test3()test3()运行结果为: 我是函数中的y为101我是函数中的y为102我是函数中的y为103注意事项
- 未使用
global时,函数内赋值会默认创建局部变量。 - 尝试在全局访问局部变量会引发
NameError(如print(c))。 - 循环结构(如
while)不形成独立作用域,其内部变量遵循所在函数或全局的作用域规则。
函数嵌套的基本概念
函数嵌套指的是在一个函数的执行过程中调用另一个函数。这种调用可以是直接的,也可以是间接的(通过多层调用)。
示例分析
示例1:直接嵌套调用
defone(name,msg):print(f'我叫{name},我想说{msg}')two(msg)print('one函数结束了')deftwo(msg):print('*********')print(msg)print('*********')one("小明","很高兴认识你")运行结果为: 我叫小明,我想说很高兴认识你*********很高兴认识你*********one函数结束了- 函数
one在内部调用了函数two,并将参数msg传递给two。 - 调用顺序:
one->two-> 返回one继续执行剩余代码。
示例2:多层嵌套调用
deftest1():print('进入test1')test2()print('退出test1')deftest2():print('进入test2')test3()print('退出test2')deftest3():print('进入test3')print('执行函数33333333')print('退出test3')test1()运行结果为: 进入test1 进入test2 进入test3 执行函数33333333退出test3 退出test2 退出test1- 函数
test1调用test2,test2又调用test3。 - 调用顺序:
test1->test2->test3-> 返回test2-> 返回test1。
嵌套调用的特点
- 执行流程:嵌套调用遵循“先进后出”的原则,类似于栈结构。被调用的函数执行完毕后,控制权会返回到调用它的函数。
- 参数传递:调用时可以通过参数将数据传递给被调用的函数。
- 代码复用:通过嵌套调用,可以避免重复编写相同的逻辑,提高代码复用性。
- 调试复杂性:多层嵌套可能导致调试困难,需注意调用链的清晰性。
注意事项
- 避免无限递归:如果函数间接或直接调用自身,可能导致无限递归。
- 控制嵌套深度:过深的嵌套会降低代码可读性,建议合理拆分函数。
递归调用的基本概念
递归调用指的是函数在执行过程中直接或间接调用自身的操作。递归通常包含两个关键部分:基线条件(终止条件)和递归条件(继续调用自身的条件)。
递归示例分析
以下代码展示了一个简单的递归函数,打印多次"你好呀":
defhello(n):print(f'你好呀{n}')ifn>1:hello(n-1)hello(5)运行结果为: 你好呀5你好呀4你好呀3你好呀2你好呀1递归的执行顺序
递归的执行顺序取决于递归调用与操作的位置关系。以下代码展示了操作在递归调用后的执行顺序:
defhello(n):ifn>1:hello(n-1)print(f'你好呀{n}')hello(5)运行结果为: 你好呀1你好呀2你好呀3你好呀4你好呀5递归与嵌套调用的等价性
递归可以被理解为一种嵌套调用的简化形式。以下代码展示了递归与手动嵌套调用的等价性:
defhello1():print(f'你好呀1')defhello2():hello1()print(f'你好呀2')defhello3():hello2()print(f'你好呀3')defhello4():hello3()print(f'你好呀4')defhello5():hello4()print(f'你好呀5')hello5()文档字符串(函数注释)
示例
以下是一个简单的求和函数示例:
defadd(a,b):"""这是一个求和函数"""# 文档字符串returna+b add(10,20)递归的关键要点
递归必须包含明确的终止条件,否则会导致无限递归。递归的执行过程会形成调用栈,每次递归调用都会将当前状态压入栈中,直到满足终止条件才开始回溯执行。
递归可以简化代码结构,但需要注意栈溢出风险和性能问题。对于复杂问题,递归通常比循环更简洁直观,但在性能敏感场景可能需要考虑尾递归优化或改用迭代实现。
