☰
python入门学习(四)
2026/9/25 21:58:46 网站建设 项目流程
# ******** python中的函数 ******** # from email.contentmanager import maintype # from email.contentmanager import maintype from itertools import count # 1.什么是函数 # 函数是组织好的,可重复使用的、用来实现单一或者相关联功能的代码段 # 比喻:函数就像厨具里的"破壁机" 你不需要知道内部的刀片是怎么转的,只需要放入水果(输入),按下开关(执行),它就会给你出果汁(输出结果) # 2.函数的作用? # 代码复用:写一次代码,到处运行,不用重复造轮子 # 易于维护:如果逻辑要改,只需要改函数内部,所有调用的地方都会更新 # 结构清晰:把复杂的程序拆分成一个个的小模块,让代码可读性更强 # 3.定义函数的基本格式 # def 函数名(参数1,参数2,..。): # 函数的代码段 (具体要干活的代码) # return 结果 # 注意⚠:必须按照缩进来写函数,python中的缩进决定了代码的作用域 # 参数是外界传给函数内部的信息 # 形参(形式参数):定义函数时写的参数名 # 实参(实际参数):调用函数时真正传进去的值 # 代码举例 # def say_hello(name): # name 就是形参 # print(f'您好,{name}') # say_hello('未来!') # 未来! 就是实参 # 3.1 一个完整的自定义函数由以下几部分组成 # def nasa(parameter1, parameter2) -> str: # """ # 这里是 Docstring(字符串文档) # 解释函数是做什么的,参数是什么,返回值是什么 # """ # # 逻辑代码块 # result = f"{parameter1}{parameter2}" # # return result # 返回值 # 关键细节: # 1.函数名:它是指向函数对象的变量名 # 2.参数(parameters):函数定义的占位符 # 3.类型注释:如 -> str,它不会强制限制类型,但对IDE提醒和团队协作至关重要 # 3.2 参数的四种形态 # 1.位置参数:按顺序一一对应 # 2.关键字参数:nasa(name='lisi'),不按顺序也没关系 # 3.默认参数:def nasa(a=10) 切记:默认参数必须返回位置参数后面 # 4.不定长参数: # 4.1 *args:可变长元组,接收多出来的的位置参数,打包成元组(tuple) # 4.2 **kwargs:可变长字典,接收多出来的关键字参数,打包成字典(dict) # 4.函数执行的底层逻辑:找帧(stack frame) # 当你调用一个函数,python解释器会发生什么? # 1.创建栈帧:在内存中开辟一块空间,用来存放该函数的局部变量,参数等 # 2.压栈:将这个栈帧压入调用栈 # 3.执行:运行函数体代码 # 4.出栈:函数体执行完毕(遇到retur或代码结束),将栈帧被销毁,释放内存 # 这就是为什么函数内部的局部变量外面无法访问的原因,因为随着函数结束,存放这些变量的"空间"已经被拆除了 # 返回值 (retur) # 在python中,每一个函数都有返回值 # 1.如果你写了 return x,它返回 x # 2.如果没写 return,或者只写了return后面没接东西,它隐式返回 None # 3.python 可以"返回多个值",例如 return a,b 本质上,它是返回了一个包含 a 和 b 元组(tuple) # 5.什么时候该写函数? # 复用性:一段逻辑出现了两次以上,请封装它 # 单一职责:一个函数只做一件事,如果你的函数超过50行,通常意味着它承担着太多的责任,需要进行拆分 # 纯函数:理想状态下,相同的输入永远得到相同的输出,且不修改外包的局部变量,这种函数是最容易测试和维护的 # 单个参数 # def nasa(name): # """ # :param name: 姓名(中文/英文) # :return: # """ # print('我是浦东'+ name) # 函数调用 # if __name__ == '__main__': # nasa('吴彦祖') # if __name__ == '__main__': # 这个主函数,是函数的入口 # __name__:代表当前模块 # __main__:代表被运行模块 # 如果 当前模块 和 被运行模块 相等就运行,不相等就不允许 # 多个参数 # def nasa(name, age): # """ # :param name: # :param age: # :return: # """ # print('我是浦东' + name + '我今年' + age + '岁了!') # # if __name__ == '__main__': # nasa('吴彦祖', '18') # 默认参数 # def nasa(name='老六',age='18'): # """ # :param name: # :param age: # :return: # """ # print('我是浦东' + name + '我今年' + age + '岁了!') # # if __name__ == '__main__': # nasa(name='吴彦祖') # 可变长元组 * # def nasa(*args): # * 就是专门处理散装的、按顺序排列的值(可传多个固定值) # *args指的是把所有传进来的。没有指定名字的参数通通塞进一个元组里 # """ # :param values: # :return: # """ # print(args) # # if __name__ == '__main__': # nasa('zhangsan','lisi','laoliu') # 可变成字典 ** # def nasa(**kwargs): # **kwargs 指的是把所有传进来的。带有名字的参数,通通打包成一个字典 # """ # kw: 代表 keyword(关键字) args代表arguments(参数) # :param kwargs: # :return: # """ # print(kwargs) # # dcs = { # "name": "zahangsan", # "age": "18", # "sex": "1" # } # # if __name__ == '__main__': # nasa( name='吴彦祖', age='18') # def nasa(*args,**kwargs): # print(f'位置参数(元组):{args}') # print(f'关键字参数(字典):{kwargs}') # # if __name__ == '__main__': # nasa(1,2,3, name='吴彦祖', age='18') # python中的返回值 # print()输出的是一个不可改变的结果,return输出的是一个可供调用的变量 # def nasa(a): # b = a + 1 # print(b) # return b # # # if __name__ == '__main__': # bell = nasa(3) # print(bell) # ******** python中的作用域 ******** # 作用域(scope)规则:变量在哪里定义,就在哪里起作用;如果到处都有,那就由进及远找 # 在python中,这套原则被称为LEGB原则 # 1.LEGB:变量的查找顺序 # 当你在函数中去使用一个变量名时,python会按照以下顺序在四个"仓库"里去查找,一旦找到就停止搜索,如果全找完都没有,那么会报错 NameError # 1.1 L (local)-局部作用域:函数内部定义的变量 # 1.2 E (Enclosing) - 嵌套(闭包)作用域:外部函数里,但不在内部函数里的变量 # 1.3 G (Global) - 全局作用域:模块最顶层定义的变量(通常是文件开头写的) # 1.4 B (Built-in) - 内置作用域:python自带的函数,如 len、print、int等 # 场景演示:谁才是个"角色"? # x = '全局变量' # def outer(): # x = '嵌套变量' # # def inner(): # x = '局部变量' # print(f'我在 inner 里,我看到的是:{x}') # 我在 inner 里,我看到的是:局部变量 # # inner() # print(f'我在 outer 里,我看到的是:{x}') # 我在 outer 里,我看到的是:嵌套变量 # if __name__ == '__main__': # outer() # print(f'我在最外面,我看到的是:{x}') # 我在最外面,我看到的是:全局变量 # 3.只读不改:作用域的 "屏障" # 这是最核心的重点:在函数内部,你可以直接读取全局变量的值,但不能直接改变它 # 如果你尝试修改,python会以为你想在函数里创建一个同名的局部变量,从而引发混乱 # 错误❌示范 # count = 0 # def nasa(): # count = count + 1 # 报错:UnboundLocalError # # python 认为你在引用局部变量,但还没定义它 # # if __name__ == '__main__': # nasa() # 4.破壁术:global 和 nonlocal # 如果你非要在函数内部修改外部的变量,你需要申请 "通行证" # 修改全局变量: global # count = 0 # def nasa(): # global count # 声明 :我要东外面那个 count # count = 5 # if __name__ == '__main__': # nasa() # print(count) # 5 # 修改嵌套变量:nonlocal # 这在闭包(函数嵌套函数)中非常有用 # def nasa(): # money = 10 # def bell(): # nonlocal money # money += 100 # bell() # print(money) # # if __name__ == '__main__': # nasa() # 5.为什么作用域这么重要? # 5.1 避免污染:如果没有作用域,全部的变量名都不能重复,你在函数a用了i,函数b里的i会被误改 # 5.2 内存回收:当函数执行完,L(局部变量)所在的仓库就会被销毁,去释放内存,如果里面所有的东西都是全局,电脑内存很快就会爆掉 # 如果你在函数里写了 len = '哈哈😄',然后又想用 len([1,2]),会发生什么? # 答案:python会在L找len,发现它是一个字符串,于是报错说字符串不能当函数去调用,这就是局部变量"屏蔽"了内置函数 # 6.什么是闭包?(函数的进阶用法) # 闭包本质也是一个函数,但比普通函数多了一个 "随身背包",这个背包里面装的是它被创建时,周围环境的变量 # 专业定义 # 如果一个内部函数引用了外部函数的变量,并且外部函数返回了这个内部函数,那么这个内部函数连同它引用的变量,就组成了一个闭包 # 7.为什么要用闭包 # 7.1 数据封装:在全局定义的变量谁都能改,不安全,闭包里的变量只要内部函数能访问 # 7.2 保持状态:普通函数运行完,内部变量就 "失忆"了,闭包能让变量在多次调用直接持续存在 # 7.3 减少参数冗余:如果你有一个参数在很多次调用都是一样的,闭包可以帮你 "预设"好这个参数 # 8.怎么使用闭包 # 场景:计算历史所有输入的平均值 # def make_avgrager(): # # 1.外部函数的局部变量 # series = [] # series: [10,11] # # def avgrager(new_value): # new_value: 11 # # 2.内部函数引用了外部变量 # series.append(new_value) # total = sum(series) # tatal: 21 # return total / len(series) # # # 3.返回内部函数(不带括号) # return avgrager # # if __name__ == '__main__': # avg = make_avgrager() # print(avg(10)) # print(avg(11)) # print(avg(12)) # 场景:加法器 # 外函数传一个"底数",内函数负责把新数加在底数上 # def box(num1): # # num1 是外函数的变量 # def add(num2): # # 内函数引用了 num1 # return num1 + num2 # # return add # # if __name__ == '__main__': # # 1.创建一个 "加10" 的机器 # add10 = box(10) # 输出15 (10+5) # # 2.创建一个 "加100" 的机器 # add100 = box(100) # 输出105 (100+5) # print(add10(5)) # print(add100(5)) # 1.num1 是怎么拿到值的 # num1 的值是在创建机器的时候,就被 "缝进去了" # 动作:当你写 add10 = box(10),你就调用了 box # 发生过程:box 接收到了数字10,把它存在自己的变量 num1,此时,它发现内部的add函数需要用到这个 num1 # 结果:在 add被扔出来(return)的那一刻,python自动给add10做了一个随身口袋,把10塞了进去 # 结论:num1 是add10诞生时就自带的 "出厂设置",它不需要你后来告诉它,它一直随身带着 # 2.num2 是怎么拿到值的 # 动作:在你写add(5),你实际上是在给这个已经成型的机器 "喂" 数据 # 发生过程:这里(5)就是直接给add函数(也就是现在add10)的第一个位置参数 # 结果:此时,add开始工作,它把传进来的5 放在了定义的num2这个位置上 # num2是一个 "临时工" 这次你传5它就是5,你下次传8它就是8 # 3.它们是怎么合体的? # 当add10(5)运行到return num1 + num2 这一行的时候,它会做两件事 # 3.1 翻口袋:它从随身口袋摸出那个早就在那里的10,也就是num1 # 3.2 看手心:它看看你刚喂给它的那个5(也就是num2) # 3.3 做加法:10 + 5 = 15 # 9.匿名函数 # 什么是匿名函数? # 在python中,匿名函数使用 lambda关键字定义,它被称为 "匿名函数"或 "一行函数",因为它不需要用def取名 # 基本格式 # lambda 参数1,参数2,... :表达式 # 9.2怎么使用? # 先定义一个普通函数来看一下和匿名函数的区别 # def add(x,y): # return x + y # if __name__ == '__main__': # print(add(1,1)) # 匿名函数 # nasa = lambda x, y :x + y # print(nasa(1,1)) # 什么时候使用匿名函数? # 用完即丢:这个逻辑这里只用一次,专门去def一个函数太费劲 # 代码简洁:但逻辑非常简单(一行搞定)时,lambda让代码看起来更清爽 # num = [1,2,3,4] # # 把每个数求平方 # nasa = map(lambda x:x * x,num) # print(list(nasa)) # 10.函数的传递 # 需求:编写一个求平均值的函数,然后根据各科成绩平均分判断是否为优秀学生(分数≥80为优秀学生) # def avg_score(num): # score = num / 6 # return score # # def score(fs): # """函数传递""" # value = avg_score(fs) # if value >= 80: # print('优秀学生') # else: # print('不是优秀学生') # # if __name__ == '__main__': # score(400) # 第一题:【外卖后台自动调价系统】 # 1. 场景背景: # 你正在为“饿了么”编写一个订单结算函数。 # 后台接收到的数据比较杂乱:既有店铺名称,也有顾客备注的一些赠品(没有价格),还有真正的计价菜品(有键值对价格)。 # 2. 业务规则(输入): # shop_name:字符串,代表店铺名字(必须接收)。 # *foods:接收所有“只提名字、不计金额 ”的赠品或餐具(如:"筷子", "纸巾", "赠送小菜") # **prices:接收所有“菜品名=价格”的计价对(如:pizza=88, coke=12)。 # 3. 逻辑处理(过程): # 计算总价:只累加 prices 里的金额,忽略 foods 里的赠品。 # 满减政策:如果计算出的总金额 满 100 元,系统自动判定为大额订单,给予 8 折 优惠。 # 打印清单:在函数内部打印出店名和所有获赠的赠品清单。 # 4. 任务结果(输出): # 返回最终客户需要支付的结算金额(浮点数)。 # 5、输出示例 # --- 正在处理【好味小吃店】的订单 --- # 备注赠品: 多加辣 / 要餐具 # 订单A结算金额: 40 元 # # --- 正在处理【必胜客】的订单 --- # 备注赠品: 不要吸管 # 系统消息:订单满100元,已触发8折优惠! # 订单B结算金额: 96.0 元 # def nasa_order(shop_name, *foods, **prices): # """ # :param shop_name: 店铺名称 # :param foods: 赠品或者备注(*args -> 元组) # :param prices: 菜品以及价格(**kwargs -> 字典) # :return: # """ # print(f'--- 正在处理【{shop_name}】的订单 ---') # # 1.处理赠品清单 # if foods: # print(f"备注赠品:{'/'.join(foods)}") # else: # print(f'备注赠品:无') # # # 2.计算总价(**kwargs) # # prices.values() 拿到字典里所有价格的数字 # total_price = sum(prices.values()) # # 3.执行满逻辑 # if total_price >= 100: # print('系统消息:订单满100元,已触发8折优惠!') # total_price = total_price * 0.8 # return round(total_price,2) # 保留小数前两位 # # if __name__ == '__main__': # order_A = nasa_order('好味小吃店','多加辣/要餐具',pizza=20, coke=20) # print(f"订单A结算金额:{order_A}元") # print(f"订单A结算金额:{order_A:.2f}元") # 保留小数后两位 # order_B = nasa_order('必胜客', '不要吸管', pizza=80, coke=40) # print(f"订单B结算金额:{order_B}元") # 第二题:【万能智能插座系统】 # 1. 场景背景: # 想象你正在开发一款智能家居控制中心的底层逻辑。 # 你的中心有一个** "万能插座 " **(主函数),它本身并不关心插在上面的是什么电器。 # 它的唯一职责是:检测电流 -> 接通电源 -> 触发电器开关。 # 2. 角色分工(逻辑拆解): # 指令集(子函数/电器):这是具体的执行逻辑。不同的电器有不同的工作反馈,但它们都等待着被 "启动"。 # 调度中心(主函数/插座):这是一个 "高阶"容器。它预留了一个接口(参数名),等待你把某个电器的 "启动指令"传进去。 # 3. 业务规则(任务要求): # 步骤 A:定义"电器逻辑" # 定义 start_fan():打印 “🌀 [风扇] 接收到电流,叶片开始转动...”。 # 定义 start_lamp():打印 “💡 [台灯] 接收到电流,灯丝开始发光...”。 # 步骤 B:定义"调度逻辑" # 编写主函数 power_strip(device_func)。 # 处理流程: # 1、打印 “⚡ [系统] 检测到设备接入,正在安全通电...” # 2、执行传进来的 device_func。 # 3、打印 “✅ [系统] 设备运行稳定。” # 步骤 C:模拟运行 # 分别演示如何通过 “插座” 来启动 “风扇” 和 “台灯” # 示例输出: # ⚡ [系统] 检测到设备接入,正在安全通电... # 🌀 [风扇] 接收到电流,叶片开始转动... # ✅ [系统] 设备运行稳定。 def start_fan(): print('🌀 [风扇] 接收到电流,叶片开始转动...') def start_lamp(): print('💡 [台灯] 接收到电流,灯丝开始发光...') def power_strip(device_func): print('⚡ [系统] 检测到设备接入,正在安全通电...') device_func() print('✅ [系统] 设备运行稳定。') if __name__ == '__main__': print(f'---- 正在测试风扇 ----') power_strip(start_fan) print(f'---- 正在测试台灯 ----') power_strip(start_lamp)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询