变量作用域变量作用域变量生效的范围分为局部变量和全局变量局部变量定义在函数内部只能在函数里面使用函数执行结束后局部变量就销毁def testA(): a10 print(a) testA() # print(a) # 编译报错 局部变量只能在函数里使用出了作用域就销毁在函数外面无法访问函数内部定义的局部变量全局变量定义在函数外部函数内部、外部都可以读取使用# 全局变量 a100 def testA(): print(a) # 读取全局变量a def testB(): print(a) # 读取全局变量a testA() # 100 testB() # 100坑点函数内直接赋值变量会创建【局部变量】不会修改全局变量a100 def testA(): print(a) def testB(): a200 print(a) # 这里不是修改全局变量a ,而是创建一个局部变量a testA() # 100 testB() # 200只要在函数内部写 变量 值Python 默认认为这是局部变量不会改动外面的全局变量global 关键字global 关键字在函数内部修改全局变量a100 def testA(): print(a) def testB(): global a # 声名下面的a是全局变量 a200 print(a) testA() # 100 testB() #200 print(f全局变量a{a}) # 全局变量a200总结局部变量函数内定义仅函数内可用函数结束销毁全局变量函数外定义函数内可以读取直接赋值不会修改全局变量函数内想要修改全局变量必须先用global 变量名声明多函数程序执行流程多个函数之间共享数据有两种常用方式全局变量共享、返回值 参数传递方式 1共用全局变量全局变量在函数外部定义所有函数都可以访问配合global关键字函数可以修改全局变量修改后的结果其他函数也能读到#1.定义全局变量 glo_num 0 def test1(): global glo_num # 修改全局变量 glo_num 200 def test2(): # 调用test1修改后的全局变量 print(glo_num) # 调用test1 执行函数内部代码声明和修改全局变量 test1() # 调用test2,执行函数内部代码打印全局变量 test2()全局变量的特点一处修改全部函数可见方式 2返回值作为参数传递特点解耦减少全局变量a不使用全局变量b函数 1 把结果用return返回保存到变量c再把这个变量作为参数传给函数 2def test1(): return 50 def test2(num): return num # 1. 保存函数test1的返回值 resulttest1() # 2. 将函数返回值所在变量作为参数传递到test2函数 print(result)执行流程a定义test1、test2函数仅定义不执行内部代码bresult test1()调用 test1执行到return 50函数结束把50返回赋值给resultctest2(result)把result50传入 test2test2 内部打印50优点数据只在需要的时候传递不会污染全局空间工程开发更推荐两种方式对比知识点补充函数定义的时候不会执行函数内部代码只有调用函数函数名()的时候才会执行函数里面的代码函数的返回值return 的特性return 的特性遇到 return函数立刻结束return 的作用返回数据 终止当前函数return 后面的代码不会执行def return_num(): return 1 return 2 # 这一行永远不会执行 reuslt return_num() print(reuslt) # 输出 1函数执行碰到第一个return就退出函数后面代码直接跳过函数返回多个数据写法return 值1, 值2, 值3def return_num(): return 1,2 resultreturn_num() # reuslt return_num() print(result) # (1, 2)要点areturn a,b 一次性返回多个值时默认打包成元组 (tuple)breturn 后面也可以写列表、字典来返回多个数据return 后面写列表、字典来返回多个数据def return_num1(): return [1,2] def return_num2(): return {a:1,b:2} result1return_num1() result2return_num2() print(result1) # [1, 2] print(result2) # {a: 1, b: 2}解包接收多个返回值可以用多个变量一次性接收返回的多个结果def return_num(): return 10,20 num1,num2return_num() print(num1) # 10 print(num2) # 20核心总结1return把数据返回给函数调用处同时终止函数执行return 下方代码不再运行2多个返回值写法return 数据1,数据2默认返回元组3return 也可以返回列表、字典等容器类型实现多数据返回4可以用多个变量接收多返回值变量数量要和返回元素数量匹配函数的参数一共 4 大类参数位置参数、关键字参数、缺省 (默认) 参数、不定长参数位置参数调用函数按照定义时参数的顺序依次传值def user_info(name,age,gender): print(f你的名字是{name},年龄是{age},性别是{gender}) user_info(TOM,21,男) # 你的名字是TOM,年龄是21,性别是男注意传递的参数个数、顺序必须和函数定义保持一致否则报错关键字参数调用函数时用 形参名值 的形式传参不再受顺序限制def user_info(name,age,gender): print(f你的名字是{name},年龄是{age},性别是{gender}) user_info(Rose,age21,gender女) # 你的名字是Rose,年龄是21,性别是女 user_info(小明,gender男,age22) # 你的名字是小明,年龄是22,性别是男注意如果位置参数和关键字参数混用位置参数必须写在关键字参数前面关键字参数之间不分先后顺序缺省参数默认参数定义函数时给参数设置默认值调用函数时如果不给这个参数传值自动使用默认值def user_info(name,age,gender男): print(f你的名字是{name},年龄是{age},性别是{gender}) user_info(Tom,20) # 你的名字是Tom,年龄是20,性别是男 user_info(Rose,21,女) # 你的名字是Rose,年龄是21,性别是女注意带默认值的参数必须放在位置参数的后面定义函数的时候不定长参数可变参数不知道将来调用会传入多少个参数时使用分为两种包裹位置传递 *args1接收所有位置参数打包成元组 tupledef user_info(*args): print(args) user_info(Tom) # (Tom,) user_info(TOM,18) # (TOM, 18)要点a*args接收位置参数把所有传入的位置参数打包成元组 tuplebargs 是元组类型可以传 0 个、1 个或多个参数c命名习惯用args你也可以写*a但约定俗成写*args包裹关键字传递**kwargs1def user_info(**kwargs): print(kwargs) user_info(nameTom,age21,id241) # {name: Tom, age: 21, id: 241}要点a**kwargs接收关键字参数keyvalueb自动把所有关键字参数打包成字典 dictc命名习惯用kwargs总结1*args收集位置参数 → 打包成元组2**kwargs收集关键字参数 → 打包成字典拆包和交换变量值拆包拆包就是把容器类型元组、列表、字典等里面的元素一次性赋值给多个变量元组拆包def return_num(): return 100,200 # 等价于 return(100,200) 返回元组 num1,num2return_num() print(num1) # 100 print(num2) # 200原理a函数返回 100,200Python 默认打包成元组 (100, 200)bnum1, num2 元组 → 自动拆包第 1 个元素给 num1第 2 个给 num2字典拆包dict1{name:Tom,age:21} a,bdict1 # 对字典进行拆包取出来的是字典 print(a) # name print(b) # age print(dict1[a]) # Tom print(dict1[b]) # 21重点a字典直接拆包拿到的是字典的键key不是值 valueb拿到 key 之后再用 dict[key] 才能取出对应的值组包 ↔ 拆包1组包*args把多个位置参数打包成元组**kwargs把关键字参数打包成字典2拆包把元组 / 字典里面的元素解开赋值给变量拓展函数传参时的拆包1元组拆包传参 *def func(a,b): return (a,b) t(10,20) print(func(*t)) # (10, 20)2字典拆包传参 **def func(name,age): return (name,age) d{name:TOM,age:21} # func(**d) **d 字典拆包等价funct(nameTOM,age21) print(func(**d))交换两个变量的值需求a 10b 20交换 a 和 b 的值方法 1借助第三方中间变量a10 b20 # 1. 定义中间变量c,先保存a的值 ca # 2.把b赋给a ab # 3. 把c中保存a的原始值赋值给b bc print(a) # 20 print(b) # 10执行过程拆解ac a→ c 10把 a 的 10 存起来ba b→ a 20a 被 b 的值覆盖cb c→ b 10用 c 里面存的旧 a 赋值给 b缺点需要额外开辟一个变量空间方法 2Python 特有写法一行交换 a, b b, aa10 b20 a,bb,a print(a) # 20 print(b) # 20原理Python 会先计算等号右边b,a打包成元组(20,10)再依次解包赋值给左边a和b引用引用、可变类型 、 不可变类型核心概念1id()函数返回对象的内存地址编号用来判断两个变量是不是指向同一个内存对象2Python 里变量保存的不是值本身而是对象的引用内存地址3不可变类型int、str、tuple数据一旦创建内存里的值不能修改重新赋值会开辟新内存4可变类型list、dict、set内存里的数据可以原地修改不会改变对象本身的内存地址int不可变类型a1 ba print(b) print(id(a)) # 和id(b) 一样a、b同时执行内存里的1 140733331358504 print(id(b)) # 140733331358504 a 2 # 重点不是修改内存里的1而是新建对象2a 指向新地址 print(b) # b 还是指向1 print(id(a)) #140733331358536 print(id(b)) # 1407333313585041结论int 不可变修改a不会影响b2原理a2不是把原来内存里的1改成2而是在内存创建一个新对象2让变量a的引用指向它。b还指向原来的1不受影响list可变类型aa[10,20] bbaa print(id(aa)) # id(aa) 和id(bb) 相同指向同一个列表 对象 print(id(bb)) aa.append(30) # 原列表内存里原地追加元素不创建新列表id不变 print(bb) # bb 和 aa 指向的是同一个列表 print(id(aa)) # 地址没变 print(id(bb)) #地址没变1结论list 可变原地修改列表所有指向这个列表的变量都会看到变化2区分aaa.append()原地修改id 不变baa [1,2,3]重新赋值创建新列表id 会改变总结1ba把 a 的引用内存地址赋值给 b两个变量指向同一个对象2不可变类型想改值 → 新建对象互不干扰3可变类型原地修改对象 → 所有共享这个引用的变量一起变化